5 Replies Latest reply on Oct 7, 2015 2:23 AM by mkouba

    Has rawType handling changed between CDI 1.0/1.2?

    starksm64

      So I'm reviving an old CDI 1.0 based application that I was running using weld and javase, and I'm seeing differences with how producer method are being matched up. The one case that no longer works involves a producer method like:

       

      @Produced
      @Produces

      public static IStrategyStateMachineFactory getStrategySM(InjectionPoint ip, BeanManager beanManager) {

      ...

      }

       

      with an injection point like:

       

      @Named("ParameterizedSTPCOStrategy")

      public class ParameterizedSTPCOStrategy<S extends Enum, T extends Enum> extends NamedStrategy {

      @Inject
      @Produced
      private IStrategyStateMachineFactory<S, T, IStrategyStateHandler<S, T>> factory;

      ...

       

      and the IStrategyStateMachineFactory interface is:

      public interface IStrategyStateMachineFactory<S extends Enum, T extends Enum, H> {

      ...

      }

       

      While this worked with CDI 1.0, this now fails with an unsatisfied dependency:

       

      Exception in thread "main" org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type IStrategyStateMachineFactory<S, T, IStrategyStateHandler<S, T>> with qualifiers @Produced

        at injection point [BackedAnnotatedField] @Inject @Produced private com.si.strategy.ParameterizedSTPCOStrategy.factory

        at com.si.trading.strategy.ParameterizedSTPCOStrategy.factory(ParameterizedSTPCOStrategy.java:0)

      ...

       

      Ok, so I changed the producer method to use a generic method:

      public static <S extends Enum, T extends Enum> IStrategyStateMachineFactory<S, T, IStrategyStateHandler<S, T>> getStrategySM(InjectionPoint ip, BeanManager beanManager) {

      ...

       

      and while this now does match the injection point, the code in the getStrategySM method to find beans that support the IStrategyStateMachineFactory rawType no longer matches. This code block does not produce anything because the call to the beanManager.getBeans(...) with the IStrategyStateMachineFactory rawType does not match any of the beans which implement the IStrategyStateMachineFactory interface:

       

      // Look through the IStrategyStateMachineFactory beans
      Set<Bean<?>> beans = beanManager.getBeans(IStrategyStateMachineFactory.class);

      Bean<IStrategyStateMachineFactory> smfactoryBean = null;

      for (Bean bean : beans) {

         Named named = getName(bean.getQualifiers());

         if (named != null) {

         if (named.value().equals(name)) {

        smfactoryBean = bean;

         break;

        }

        }

      }

       

      When I dug into the weld 2.3.0.Final code, it does seem as though the type closure of the managed beans includes the implemented interface, but I can't tell how exactly the beanManager.getBeans(...) call is searching the beans.

       

      So, all this is to ask:

       

      1. should the original CDI 1.0 usage still be working under 1.2?

      2. is there a simple change to get the beanManager.getBeans(...) call to return all of the managed beans that implement the IStrategyStateMachineFactory rawType? Note that I have hacked a workaround where I myself make a set of the beans implementing IStrategyStateMachineFactory in a weld Extension via the <T> void processBean(@Observes ProcessBean<T> bean) callback, and I use that set of beans rather than calling the bean manager.

       

      If this should be working, I can try to come up with a simple example that show the usage and create a jira issue.

        • 1. Re: Has rawType handling changed between CDI 1.0/1.2?
          mkouba

          Hi Scott,

          1. should the original CDI 1.0 usage still be working under 1.2?

          No, this must not work in CDI 1.1+. Actually, the behavior was undefined in CDI 1.0 and clarified in CDI 1.1 - see also CDI-517 comments and Assignability of raw and parameterized types. I am not so sure I fully understand the second question but will take a look more closely later today.

          • 2. Re: Has rawType handling changed between CDI 1.0/1.2?
            starksm64

            Thanks Martin.

             

            The second question is about why I'm no longer able to find the managed beans that implements a given interface, by passing in the raw type of the interface to BeanManager.getBeans(...). I attached a little cdi-ex.zip file with the code that shows the issue I'm running into. In the test.weld.gradle.MyProducerMethods.getMachineFactory producer method that is matched as the injection point producer, when I try to query the passed in BeanManager for the managed beans that are injectable for type test.weld.gradle.IFactory, this call returns an empty set where previously it would return all managed beans that implemented IFactory<? extends Enum>.

             

            The runMain task boots the cdi javase environment and has the output in red that previously would have returned a non-empty set of IFactory beans.

             

            [Tests 510]$ gradle runMain

            :compileJava UP-TO-DATE

            :processResources UP-TO-DATE

            :classes UP-TO-DATE

            :runMain

            17:14:23,212 INFO  [main] org.jboss.weld.Version: WELD-000900: 2.3.0 (Final)

            17:14:23,419 INFO  [main] org.jboss.weld.Bootstrap: WELD-000101: Transactional services not available. Injection of @Inject User                               Transaction not available. Transactional observers will be invoked synchronously.

            17:14:23,473 WARN  [main] org.jboss.weld.Interceptor: WELD-001700: Interceptor annotation class javax.ejb.PostActivate not found, interception based on it is not enabled

            17:14:23,474 WARN  [main] org.jboss.weld.Interceptor: WELD-001700: Interceptor annotation class javax.ejb.PrePassivate not found, interception based on it is not enabled

            processBean: Managed Bean [class test.weld.gradle.machines.fsm.FSMFactory] with qualifiers [@Any @Default]

            FSMFactory.types:[test.weld.gradle.IFactory<test.weld.gradle.machines.fsm.FSMTypes>, class java.lang.Object, class test.weld.gradle.machines.fsm.FSMFactory]

            17:14:23,748 INFO  [main] org.jboss.weld.Bootstrap: WELD-ENV-002003: Weld SE container STATIC_INSTANCE initialized

            Main.ctor, symbolMonitor=null

            Found 0 beans of type IFactory

            Failed to find bean of type IFactory

            TheStrategy.init, factory=null

            Main.init, symbolMonitor=test.weld.gradle.SymbolMonitor@610f7aa, strategy=test.weld.gradle.TheStrategy@6a03bcb1

            Created Main: test.weld.gradle.Main@672872e1

            17:14:23,763 INFO  [main] org.jboss.weld.Bootstrap: WELD-ENV-002001: Weld SE container STATIC_INSTANCE shut down

             

            BUILD SUCCESSFUL

             

            Total time: 3.223 secs

             

            This build could be faster, please consider using the Gradle Daemon: http://gradle.org/docs/2.4/userguide/gradle_daemon.html

            [Tests 511]$


            • 3. Re: Has rawType handling changed between CDI 1.0/1.2?
              mkouba

              You should use a TypeLiteral instance, i.e. something like this should work:

               

               Set<Bean<?>> beans = beanManager.getBeans(new TypeLiteral<IFactory<?>>() {}.getType());
              

               

              See also Using AnnotationLiteral and TypeLiteral.

              • 4. Re: Has rawType handling changed between CDI 1.0/1.2?
                starksm64

                Ok, so using the "?" wildcard does match, why wouldn't this variation that uses the same type as the producer method return value?

                 

                public static <E extends Enum> IFactory<E> getMachineFactory(InjectionPoint ip, BeanManager beanManager) {

                  TypeLiteral<IFactory<E>> factoryType = new TypeLiteral<IFactory<E>>() {};

                 

                For info, here are the types of the managed bean that should match as seen in the weld extension processBean callback:

                processBean: Managed Bean [class test.weld.gradle.machines.fsm.FSMFactory] with qualifiers [@Any @Default]

                FSMFactory.types:

                  java.lang.Object

                  test.weld.gradle.IFactory<test.weld.gradle.machines.fsm.FSMTypes>

                  test.weld.gradle.machines.fsm.FSMFactory

                • 5. Re: Has rawType handling changed between CDI 1.0/1.2?
                  mkouba

                  I'm not really sure why but the spec forbids to have a wildcard in a producer method return type (see also 3.3. Producer methods). The other thing is a producer method metadata is built from the method signature and its annotations (not the returning instance).