Search code examples
dependency-injectioncdiweld

How can I make Weld to distinguish [@Default@Any@Named] from [@Default@Any]?


I'm using weld-se for testing one of my JSR-330 annotated class.

@Inject HelloWorld any;
@Inject @Named("impl") HelloWorld namedAsImpl;
@Inject @Named("demo") HelloWorld namedAsDemo;
@Inject @Impl HelloWorld qualifiedWithImpl;
@Inject @Demo HelloWorld qualifiedWithDemo;

I successfully injected those fields with Guice, Dagger, and Dagger2.

I prepared a provider class.

@RequestScoped
public class HelloWorldWeldProvider {

    @Produces HelloWorld any() {
        return current().nextBoolean()
               ? new HelloWorldImpl() : new HelloWorldDemo();
    }

    @Produces @Named("impl") HelloWorld namedAsImpl() {
        return new HelloWorldImpl();
    }

    @Produces @Named("demo") HelloWorld namedAsDemo() {
        return new HelloWorldDemo();
    }

    @Produces @Impl HelloWorld qualifiedWithImpl() {
        return new HelloWorldImpl();
    }

    @Produces @Demo HelloWorld qualifiedWithDemo() {
        return new HelloWorldDemo();
    }
}

And Weld complains

WELD-001409: Ambiguous dependencies for type HelloWorld with qualifiers @Default
  at injection point [BackedAnnotatedField] @Inject ....any
  at ....any(HelloWorldDependencyInjectionTest.java:0)
  Possible dependencies: 
  - Producer Method [HelloWorld] with qualifiers [@Default @Any @Named] declared as [[BackedAnnotatedMethod] @Produces @Named ....namedAsDemo()],
  - Producer Method [HelloWorld] with qualifiers [@Default @Any @Named] declared as [[BackedAnnotatedMethod] @Produces @Named ....namedAsImpl()],
  - Producer Method [HelloWorld] with qualifiers [@Any @Default] declared as [[BackedAnnotatedMethod] @Produces ....any()]

Is this normal? or is CDI works differently than DI?`


Solution

  • Yes, this is expected. Bean resolution for injection points is governed by the Highlander Principle: "There can be only one."

    From the CDI spec:

    If a bean does not explicitly declare a qualifier other than @Named, the bean has exactly one additional qualifier, of type @Default. This is called the default qualifier.

    and

    If an injection point declares no qualifier, the injection point has exactly one qualifier, the default qualifier @Default.

    So your unqualified injection point is indeed matched by three beans.

    Your second question Is CDI different from DI? depends on your definition of DI. If you mean DI = JSR330, then the answer is yes, or else there would be no point in creating a new spec.