5 Replies Latest reply on Nov 22, 2016 2:24 AM by mkouba

    Beans with a dependent scope and an observer method - weird behavior

    steappe

      Considering the following environment:

      • Weld SE (2.4.0)
      • A Main class starting Weld SE
      • An application scoped class named Application
      • A dependent scope class named Child

       

      And the following binding:

      • Application has two injected children: son and daughter
      • Main has an injected Event class, and fires an event when the container is initialized
      • Child has an event observer that observes that event

       

      Then:

      • Why do I log only one  event message in only one Child instance?
      • Why is a third instance of the Child class created when the event is fired? (only this instance receives the event)

       

      Child is a dependent scope bean. When it's injected in the Application instance, it should be placed in the same scope as this instance, i.e. it should be placed in the Application Scope.

      When the event is fired, I can observe a behavior that is exactly at the opposite of what I would expect:

      • Son and Daughter instances, which are in scope, do not receive the event
      • An anonymous instance of Child is created when the event is fired, while this instance of Child is not placed in any scope.

       

      Is it a bug, or have I misunderstood the specifications?

        • 1. Re: Beans with a dependent scope and an observer method - weird behavior
          mkouba

          Hi Stéphane,

          this is expected behavior. When the container calls an observer method it must obtain a contextual instance first. For dependent beans this means to create a new instance (and also destroy this instance properly when the invocation completes). Note that dependent bean instances do not live in a context, they're bound to the lifecycle of the bean they depend on. See also Invocation of observer methods and Destruction of objects with scope @Dependent.

          • 2. Re: Beans with a dependent scope and an observer method - weird behavior
            steappe

            Hi Martin,

             

            Thanks for the clarification.

             

            I wonder if the CDI specifications should be clarified then, because:

            http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#observer_notificationhttp://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#observer_notification

            "If there is no context active for the scope to which the bean declaring the observer method belongs, then the observer method should not be called."

             

            And

            http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#dependent_context

            "Any instance of the bean injected into an object that is being created by the container is bound to the lifecycle of the newly created object."

            "Any instance of the bean that receives a producer method, producer field, disposer method or observer method invocation exists to service that invocation only."

             

            Can you see the confusion?

             

            I have then another question:

            Is it possible to implement a portable CDI extension in Weld-SE defining a custom scope that would behave exactly as I want, i.e. where only Son and Daughter would be notified in my example above?

            Or said it differently, where only the beans declaring an observer method and that are placed in the scope of an active context would be notified.

            If yes, a few hints about the implementation would be helpful. Thanks

            • 3. Re: Beans with a dependent scope and an observer method - weird behavior
              mkouba
              Can you see the confusion?

              Not really . The @Dependent scope is always active. These sentences simply mean that if you have a @Dependent bean with an observer method, a new bean instance is always created when the observer is about to be called, then the observer method is called upon the instance and finally, the instance is destroyed afterwards.

              I have then another question:

              Is it possible to implement a portable CDI extension in Weld-SE defining a custom scope that would behave exactly as I want, i.e. where only Son and Daughter would be notified in my example above?

              Or said it differently, where only the beans declaring an observer method and that are placed in the scope of an active context would be notified.

              If yes, a few hints about the implementation would be helpful. Thanks

              Well, this will work for any normal scope but not for @Dependent - for @Dependent the container does not hold a reference to the bean instance.

              • 4. Re: Beans with a dependent scope and an observer method - weird behavior
                steappe

                Ok got it for the @Dependent scope now. Since it's always active, then it makes perfectly sense. It's a bit counter-intuitive in a first place, but I can understand.

                 

                I've started the implementation of a custom scope @MyScoped, which would have the behavior I want, and an associated MyContext. So I have this:

                 

                @MyScoped

                class Parent {

                     @Inject Child son;

                     @Inject Child daughter;

                     public Child getSon() {return son;}

                     public Child getDaughter() {return daughter;}

                }

                 

                @MyScoped

                class Child {

                     public void foo() {}

                     private void onEvent(@Observes SomeEvent event) {

                     }

                }

                 

                For such a construct to work, I need two different instances of Child: one for son and one for daughter.

                 

                So I implemented MyContext this way:

                MyContext implements Context {

                     @Override

                     public <T> T get(Contextual<T> contextual) {

                          return null; // always return null so a new instance of the bean is created.

                     }

                }

                 

                But of course this is not working:

                Child son = parent.getSon(); // a new instance of parent is created

                Child daughter = parent.getDaughter(); // once again, a new instance of parent is created

                son.foo(); // a new instance of son is created

                son.foo(); // once again, a new instance of son is created

                 

                How can I implement the get method of MyContext, so I can have 1 instance of parent, and two instances of Child?

                I feel like I would need to have an access to the injection point of the bean, more or less the same way it's done in the DependentContext. But how can it be done in a portable way?

                • 5. Re: Beans with a dependent scope and an observer method - weird behavior
                  mkouba
                  How can I implement the get method of MyContext, so I can have 1 instance of parent, and two instances of Child?

                  I think this is not possible as long as MyScoped is a normal scope (for normal scope there's always one instance per bean per thread). So in other words, you could either have distinguish @Dependent children without observers or shared normal scoped child with observers. You may also consider invoking the observer logic manually. E.g. define the observer on Parent and delegate to all Children instances. Also I'd recommend to look at Object tree" scope prototype  and Command context example to get some more info about how contexts work in CDI.