2 Replies Latest reply on Jun 18, 2018 7:53 AM by manovotn

    Event firing/matching and parameterized types

    ljnelson

      (For background, I've read You think you know everything about CDI events… Think again! | Next Presso , so I'm at least mostly familiar with many edge cases in CDI events.)

       

      I have an AbstractFoo<? extends T> as a payload that I want to fire.

       

      T is defined as T extends MetaData.

       

      For various unimportant reasons I have to fire my payload programmatically, so I do this:

       

      final Event<Object> cdiEventMachinery = beanManager.getEvent();

      assert cdiEventMachinery != null;

      final TypeLiteral<AbstractFoo<? extends T>> eventTypeLiteral = new TypeLiteral<AbstractFoo<? extends T>>() {

          private static final long serialVersionUID = 1L;

        };

      final Event<AbstractFoo<? extends T>> broadcaster = cdiEventMachinery.select(eventTypeLiteral, someQualifiers);

      assert broadcaster != null;

       

      Obviously here broadcaster is now set up to fire my payload.  My intention is that these events should be delivered to observers looking for AbstractFoo-or-its-subclasses instances parameterized by any type that extends MetaData.

       

      Now, when I do broadcaster.fire(payload), I've noticed that observer methods like this one:

       

      private final void onFoo(@ObservesAsync @MatchingQualifier final Foo<? extends MetaDataSubclass> event) {}

       

      …do not get called.  (The ? extends MetaDataSubclass seems to be the culprit; if the observed parameter is simply, say, Object then obviously the method is notified.)

       

      Specifically, assuming that:

       

      • a MatchingQualifier literal is present in someQualifiers, and
      • MetaDataSubclass is a class that extends MetaData, and
      • Foo is a class that extends AbstractFoo

       

      …why doesn't that observer method get called?

       

      To be clear, I'm sure this isn't a bug but is something missing in my understanding.  I'd like to find out what I'm missing.

       

      Best,

      Laird

        • 1. Re: Event firing/matching and parameterized types
          ljnelson

          Here's a test case using more simple constructs:

           

            private final void collectionExtendsNumber(@Observes final Collection<? extends Number> payload) {

              System.out.println("*** collection extends Number");

            }

           

            private final void collectionExtendsInteger(@Observes final Collection<? extends Integer> payload) {

              System.out.println("*** collection extends Integer");

            }

           

            private final void collectionInteger(@Observes final Collection<Integer> payload) {

              System.out.println("*** collection Integer");

            }

           

            private final void collectionNumber(@Observes final Collection<Number> payload) {

              System.out.println("*** collection Number");

            }

           

            @Test

            public void testContainerStartup() {

              final SeContainerInitializer initializer = SeContainerInitializer.newInstance();

              assertNotNull(initializer);

              initializer.disableDiscovery();

              initializer.addBeanClasses(this.getClass());

              try (final SeContainer container = initializer.initialize()) {

                assertNotNull(container);

                final BeanManager beanManager = container.getBeanManager();

                assertNotNull(beanManager);

                final TypeLiteral<Collection<? extends Number>> literal = new TypeLiteral<Collection<? extends Number>>() {

                    private static final long serialVersionUID = 1L;

                  };

                final Event<Collection<? extends Number>> broadcaster = beanManager.getEvent().select(literal);

                assertNotNull(broadcaster);

                final Collection<? extends Number> payload = Collections.singleton(Integer.valueOf(1));

                broadcaster.fire(payload);

              }

            }

           

          In this case, only the first observer method prints anything.

           

          The main thing that I'm struggling with is that at the point where I would like to fire my payload, all I know is that it is, effectively, Collection<? extends Number>, even though it might "actually" be Set<Integer> (as in the example above).

           

          So my TypeLiteral has to be TypeLiteral<Collection<? extends Number>>, unless I'm missing something.

           

          And if it has to be TypeLiteral<Collection<? extends Number>>, then I don't know how to fire the payload in such a way that an observer of, say, Collection<? extends Integer> or Collection<Integer> would be notified.

          • 2. Re: Event firing/matching and parameterized types
            manovotn

            Hi Laird,

             

            I've added an answer to your SO crosspost, so in order not to dulicate info, here is the link.

            I am still puzzled by the last case and if I will try to get more information about that.