Search code examples
javacdiweldweld-se

Weld on Java SE does not use alternative


I have projectA, projectB, and projectC Eclipse Maven projects.

  • ProjectA contains:
    • IMyApi interface.
    • "Empty" META-INF\beans.xml file.
  • ProjectB contains:
    • IMyConfig interface.
    • MyConfigJndi implementation of IMyConfig.
    • MyApiImpl implementation of IMyApi, with a property @Inject private IMyConfig config;.
    • "Empty" META-INF\beans.xml file.
  • ProjectC contains:
    • a MyConfigAlter implementation of IMyConfig, marked as @Alternative.
    • a Main class (and method) that initializes Weld SE and retrieves a IMyApi bean.
    • a META-INF\beans.xml where MyConfigAlter is listed in the alternatives section.

Now, I run the Main class, and the IMyApi bean is successfully retrieved (as a MyApiImpl instance). But such an instance has been, in its config property, injected with a MyConfigJndi instance, instead of the alternative version (MyConfigAlter)

I am using Eclipse Luna + M2Eclipse.

What am I doing wrong?

UPDATE: I found out that using @Specializes instead of @Alternative solves the issue, but I still think it is not the proper solution (in some situation I may not have access to the "default" implementation).

UPDATE 2:

I am using Weld-se, 2.2.10.Final:

<dependency>
    <groupId>org.jboss.weld.se</groupId>
    <artifactId>weld-se</artifactId>
    <version>2.2.10.Final</version>
    <scope>runtime</scope>
</dependency>

And the initialization is simply

WeldContainer weld =
  new Weld().
    initialize();
IMyApi myApi =
  weld.
    instance().
    select(
      IMyApi.
        class).
    get();

Solution

  • Selecting an alternative using the alternatives element in the beans.xml descriptor only affects the corresponding bean archive, i.e. ProjectC in your case, as documented in Declaring selected alternatives for a bean archive. Based on that, this is logical that the ProjectB bean archive gets the MyConfigJndi implementation injected.

    Since CDI 1.2, it is possible to select an alternative globally for the application using the @Priority annotation as documented in Declaring selected alternatives for an application.

    So in your case, you could write:

    @Priority(Interceptor.Priority.Application)
    @Alternative
    class MyConfigAlter {
    }