5 Replies Latest reply on Feb 5, 2018 10:07 AM by Martin Kouba

    Is it possible that ProcessBean<X> is not fired right for producer methods?

    Laird Nelson Apprentice

      Before I file a bug, I wanted to make sure I'm not misreading anything.

       

      My understanding is that it is fine to observe a ProcessBean event in an extension.  Your observer method will be called when every bean—including producer methods, fields, etc.—is found.

       

      The specification says that a ProcessProducerMethod event will be fired in case a producer method has been discovered.  But an observer of just plain ProcessBean will still get notified.  This all works in a case like this:

       

      private final void processBean(@Observes final ProcessBean<?> event) { // note the wildcard

        // do something with every managed bean, producer method, producer field, etc.

      }

       

      However, this does not seem to behave in the same way when we're talking about producer methods and their return types.  Specifically, although the above works with an unbounded wildcard, if instead of a wildcard we specify a type, some interesting things happen.  Let's do this:

       

      // Hey, CDI, please watch for beans, including producer methods, that have a bean type of THE_RETURN_TYPE_OF_THE_PRODUCER_METHOD

      private final <THE_RETURN_TYPE_OF_THE_PRODUCER_METHOD> void processBean(@Observes final ProcessBean<THE_RETURN_TYPE_OF_THE_PRODUCER_METHOD> event) {

        // never called for any producer method returning THE_RETURN_TYPE_OF_THE_PRODUCER_METHOD!

      }

       

      Instead, what we see is:

       

      private final <THE_TYPE_OF_THE_BEAN_HOUSING_THE_PRODUCER_METHOD> void processBean(@Observes final ProcessBean<THE_TYPE_OF_THE_BEAN_HOUSING_THE_PRODUCER_METHOD> event) {

        // called for (e.g. managed) beans of type THE_TYPE_OF_THE_BEAN_HOUSING_THE_PRODUCER_METHOD; not what we want

      }

       

      So if I have:

       

      @ApplicationScoped

      public final class Factory {

        @Produces

        public Widget widgetMaker() { /*...*/ }

      }

       

      then I'm saying:

       

      private final void processEveryBean(@Observes final ProcessBean<?> event) // will see a bean containing the bean type Widget, will see Factory too

      private final void <T extends Widget> processOnlyWidgets(@Observes final ProcessBean<T> event) // will never see a bean containing the bean type Widget; will never get called in fact

       

      The specification says (in ProcessBean's javadoc):

       

      The event object type depends upon what kind of bean was discovered: […]

      • For a producer method with method return type X of a bean with bean class T, the container must raise an event of type ProcessProducerMethod.

      So either:

      (a) private final void processBean(@Observes final ProcessBean<?> event) shouldn't get called for producer method return types (but it is in fact called in these cases), or

      (b) private final <X> void processBean(@Observes final ProcessBean<X> event) is not being called for producer method beans with X among their bean types, but should be

       

      Have I misunderstood something, or is this a bug in Weld 3.0.2.Final?

        • 1. Re: Is it possible that ProcessBean<X> is not fired right for producer methods?
          Laird Nelson Apprentice

          Made it even simpler.

           

          A (valid) producer method like this:

          @Produces public Integer fortyTwo() {  return Integer.valueOf(42); }

          …is not observed by:

          private final void processBean(@Observes final ProcessBean<Integer> event) { /* ?! */ }

          ...or:

          private final void processBean(@Observes final ProcessBean<? extends Number> event) { /* ?! */ }

          ...or:

          private final void processBean(@Observes final ProcessBean<Object> event) { /* obviously */ }

          ...but is observed by:

          private final void processBean(@Observes final ProcessBean<?> event) { /*...*/ }

          …and the toString() output of event.getBean().getTypes() at that point is:

          [class java.lang.Number, class java.lang.Integer, interface java.io.Serializable, class java.lang.Object, java.lang.Comparable<java.lang.Integer>]
          • 2. Re: Is it possible that ProcessBean<X> is not fired right for producer methods?
            Martin Kouba Master

            Hi Laird,

            this works as designed. ProcessProducerMethod<T, X> extends ProcessBean<X> where <T> is the return type of the producer method and <X> is the class of the bean declaring the producer method. In other words, a ProcessBean observer may observe any kind of bean (managed, producer, synthetic, ...) but the only "filter available" is the bean class as defined by javax.enterprise.inject.spi.Bean.getBeanClass().

            • 4. Re: Is it possible that ProcessBean<X> is not fired right for producer methods?
              Laird Nelson Apprentice

              mkouba  wrote:

               

              Hi Laird,

              this works as designed. ProcessProducerMethod<T, X> extends ProcessBean<X> where <T> is the return type of the producer method and <X> is the class of the bean declaring the producer method. In other words, a ProcessBean observer may observe any kind of bean (managed, producer, synthetic, ...) but the only "filter available" is the bean class as defined by javax.enterprise.inject.spi.Bean.getBeanClass().

              Thank you.  So why for a producer method that returns Integer defined by some other bean of type X do I get notified in an observer method like private final void processBean(final ProcessBean<?> event)?  Are you saying that I'm being notified because my bean of type X has been processed, not because my bean of type T has been processed?  Doesn't my producer method define another bean whose types are Integer and Object?   Thanks for your help.

               

              Anyway, my takeaway is that if I want to be notified of the processing of all beans with a type of Integer, whether they're managed beans, producer methods, etc. I can't do it in one place.  Is that correct?

              • 5. Re: Is it possible that ProcessBean<X> is not fired right for producer methods?
                Martin Kouba Master

                Well, a ProcessBean<?> observer is notified of any bean registered. Note that ProcessBean is a superclass of ProcessProducerMethod. E.g. if there is a class Foo which declares a producer method produce() with return type Integer, Weld fires a ProcessProducerMethod<Integer, Foo> instance which also has ProcessBean<Foo> in its set of event types and this event type is assignable to the observed event type ProcessBean<?>.

                Anyway, my takeaway is that if I want to be notified of the processing of all beans with a type of Integer, whether they're managed beans, producer methods, etc. I can't do it in one place.  Is that correct?

                It depends. In CDI there are two important bean attributes: 1. bean class - class of the bean or of the bean that declares the producer (can be anything for custom beans) which is used e.g. to determine enabled alternatives, 2. bean types - the set of types used during typesafe resolution. ProcessBean event only allows to filter by bean class, but you can always inspect the bean types using ProcessBean.getBean().getTypes().