14 Replies Latest reply on Dec 7, 2016 3:03 AM by mkouba

    Programmatically added observer methods and lifecycles

    ljnelson

      I had a question about what happens when you programmatically add an observer method to a bean.

       

      In my case, I am programmatically adding an observer method that @Observes @Initialized(ApplicationScoped.class) final Object payload.

       

      If I explicitly code up this observer method and actually add it to the source code of my bean, I notice that (as I would of course expect) the bean is instantiated by the container when the observer method is notified (section 5.5.6 of the specification requires this).  That is, upon startup a contextual instance of the bean is created so that this observer method may be called.  This has the nice side effect of allowing me to perform certain actions at startup.

       

      Now, if I do not have this method in my source code, but instead, using a portable extension, programmatically add an observer method that does the same thing, I observe that the bean is not instantiated by the container when the observer method is notified.

       

      At some level, this makes sense: in order to invoke the source-code-defined observer method, obviously there needs to be an object to invoke it on!  And in the programmatically-added case, the observer method kind of stands on its own, so can conceivably be invoked without requiring that the bean be instantiated.

       

      But on the other hand, this seems like a strange disparity caused only by where the observer method happens to be.

       

      I also recognize that I could build my programmatically-added observer method with a Function that uses the BeanManager's getReference() method to obtain a contextual reference to my bean.

       

      My real question, then, is: is this an oversight?  Should the container instantiate the bean when a programmatically added observer method is notified?

        • 1. Re: Programmatically added observer methods and lifecycles
          ljnelson

          The specification reference in question is JSR 365: Contexts and Dependency Injection for Java 2.0 section 5.5.6.  It seems that this makes no distinction between programmatically-added observer methods and programmer-authored observer methods.  If there is no other section in the specification addressing this area, then I believe that the observed behavior constitutes a specification violation here, right?

          • 2. Re: Programmatically added observer methods and lifecycles
            meetoblivion

            What version of weld are you using?

            • 3. Re: Programmatically added observer methods and lifecycles
              ljnelson

              3.0.0 Alpha 17.

              • 4. Re: Programmatically added observer methods and lifecycles
                mkouba

                Hi Laird,

                it's not possible to "programmatically add an observer method to a bean". You can either define the observer method in the source code (bean instance is created to receive notification) or add a custom implementation of ObserverMethod which is not bound to any bean (ObserverMethod.notify() is called for notification). See also "10.5. Observer notification":

                For a custom implementation of the ObserverMethod interface defined in The ObserverMethod interface, the container must call getTransactionPhase() to determine if the observer method is transactional observer method, and notify() to invoke the method.
                • 5. Re: Programmatically added observer methods and lifecycles
                  ljnelson

                  Martin Kouba wrote:

                   

                  Hi Laird,

                  it's not possible to "programmatically add an observer method to a bean". You can either define the observer method in the source code (bean instance is created to receive notification) or add a custom implementation of ObserverMethod which is not bound to any bean (ObserverMethod.notify() is called for notification). See also "10.5. Observer notification":

                  For a custom implementation of the ObserverMethod interface defined in The ObserverMethod interface, the container must call getTransactionPhase() to determine if the observer method is transactional observer method, and notify() to invoke the method.

                  I see.  Thank you.  A related question: what purpose does the beanClass(Class) method on ObserverMethodConfigurator serve (particularly with respect to custom implementations)?

                  • 6. Re: Programmatically added observer methods and lifecycles
                    mkouba

                    I think there's no purpose with respect to custom observer methods. The only thing that comes to my mind is that we can use the bean class to identify the bean archive "where the observer comes from" (similarly as we do for custom beans). I would return the extension class.

                    • 7. Re: Programmatically added observer methods and lifecycles
                      ljnelson

                      Thank you.  One last question on this subject: I've noticed that the custom observer methods seem to fire after developer-authored observer methods.  I assume this is just implementation-specific, and that the developer-authored observer method ordering mechanism applies to custom observer methods as well?  That is, I assume that ObserverMethodConfigurator::priority(int) shares a priority space with developer-authored observer methods?

                      • 8. Re: Programmatically added observer methods and lifecycles
                        mkouba

                        Yes, both @Priority and ObserverMethodConfigurator.priority() are "materialized to" ObserverMethod.getPriority(). And the ordering of observers with the same priority is undefined.

                        • 9. Re: Programmatically added observer methods and lifecycles
                          ljnelson

                          Thank you.  Curiously, as a side note, I just realized that the specification never mentions explicitly that all mentions of @Priority are to javax.interceptors.Interceptor.Priority, and not javax.annotation.Priority.  (I know that javax.annotation.Priority can be applied only to types, and that in most, but not all, cases where it is relevant the specification says it extends the interceptors specification, thus implying that javax.interceptors.Interceptor.Priority is the annotation in question, but being explicit in the specification about which annotation is being discussed would seem to be helpful.  In the observer methods section, for example, it doesn't say that it extends the interceptors specification, nor does it say what package defines the Priority annotation, nor the constants to be used.)

                          • 10. Re: Programmatically added observer methods and lifecycles
                            mkouba

                            Well, javax.interceptor.Interceptor.Priority is not an annotation. @Priority in CDI spec always refers to javax.annotation.Priority. Note that there is javax.annotation-api 1.3 MR where Priority has @Target({TYPE,PARAMETER}). 

                            • 11. Re: Programmatically added observer methods and lifecycles
                              ljnelson

                              Martin Kouba wrote:

                               

                              Well, javax.interceptor.Interceptor.Priority is not an annotation. @Priority in CDI spec always refers to javax.annotation.Priority. Note that there is javax.annotation-api 1.3 MR where Priority has @Target({TYPE,PARAMETER}).

                              Duh; goodness, that was stupid on my part; sorry.  So, wait, then to what constant field does, say, APPLICATION refer?  I didn't see such a constant in JSR 250 (the Annotations 1.3 MR you referenced).  Sorry if this is an obvious question.  I'm probably just not searching the CDI specification or the annotations specification properly.

                              • 12. Re: Programmatically added observer methods and lifecycles
                                mkouba

                                Yes, the constant values come from javax.interceptor.Interceptor.Priority (e.g. javax.interceptor.Interceptor.Priority.APPLICATION). The Priority annotation has more general use. But it was first used for interceptors. And so CDI reused the constants for decorators, alternatives and observer methods.

                                • 13. Re: Programmatically added observer methods and lifecycles
                                  ljnelson

                                  Great; sorry to have missed this.  So to be clear, the specification uses (a) the javax.annotation.Priority annotation as defined by the annotations specification version 1.3 MR (as defined by JSR 250), with (b) values for its value element supplied by javax.interceptor.Interceptor.Priority when otherwise unqualified all-capitals words (like APPLICATION) are used?  It would be great to have this spelled out explicitly.  Thanks!

                                  • 14. Re: Programmatically added observer methods and lifecycles
                                    mkouba

                                    Yep, good point. Feel free to create a spec issue. Such a small change could make it into CDI 2.0 (even if there is a feature freeze right now).