With the structure that you are describing, there is no way to obtain the desired injection.
The EJB classloader will never be able to access the classes inside the WAR , hence the injection will never consider the alternative implementation.
A solution is possible if you are willing to alterate the EAR structure, placing the alternative (D) in a lib/jar , along with the appropriare beans.xml
. The D class will become visible to your EJB and to your WAR, and the injection shoul proceed as desired.
EDIT
The solution you posted, which I descibe here, is almost working.
EAR
- ejb-module-1.jar
- A.class (@Inject I)
- I.class
- C.class (@Stateless implements I)
- META-INF/beans.xml
- ejb-module-2.jar
- D.class (@Alternative @Stateless implements I)
- META-INF/beans.xml (<alternatives><class>D</class></alternative>)
- app.war
- calls A.test()
- WEB-INF/beans.xml
The only catch is that you misplaced the beans.xml
alternative declaration.
The CDI specification (1.1, but applicable as well to the previous implementation) states at chapter 5.1 that:
An alternative is not available for injection, lookup or EL resolution to classes or JSP/JSF pages in a module unless the module is a bean archive and the alternative is explicitly selected in that bean archive.
In other words, you must select the alternative in the same module of the class which uses the bean.
Here is the revised (and working) structure:
EAR
- ejb-module-1.jar
- A.class (@Inject I)
- I.class
- C.class (@Stateless implements I)
- META-INF/beans.xml (<alternatives><class>D</class></alternative>)
- ejb-module-2.jar
- D.class (@Alternative @Stateless implements I)
- META-INF/beans.xml (empty <beans></beans>)
- app.war
- calls A.test()
- WEB-INF/beans.xml (empty <beans></beans>)
Also remember that, although for standard beans the alternative selection works only for the module in in witch the alternative is declared in beans.xml
, the same is not true for EJBs. So your D
alternative, (being @Stateless
) is valid for the entire application.