How to insert @Alternative with WAR CDI from EJB module

I want CDI to β€œpick” an alternative class as an implementation of an interface.

While all the links are in the EAR, the alternative implementation will be in the war file, and the rest (the class that introduces the interfaces, interface, "Default" interface implementation) will be in the ejb bank.

Here is the code to illustrate it:

EJB module:

public interface I {} 

 public class C implements I {} 

 public class A { @Inject I var public void test() { System.out.println(var instanceof C); // I want to have here as Result: false } } 

WAR module:

 @Alternative public class D implements I {} 

Installing beans.xml in a military file did not help ..

+4
source share
2 answers

With the structure you describe, there is no way to get the desired injection.

The EJB classloader will never be able to access classes inside the WAR, so the injection will never consider an alternative implementation.

The solution is possible if you want to change the structure of the EAR by placing the alternative (D) in lib / jar along with appropriare beans.xml . Class D will become visible to your EJB and your WAR, and the injection went as desired.

EDIT

The solution you posted that I describe here almost works.

 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 missed out on the beans.xml alternate declaration.

The CDI specification (1.1, but also applicable to the previous implementation) states in chapter 5.1 that:

An alternative is not available for injecting, searching, or resolving EL to JSP / JSF classes or pages in a module unless the module is a bean archive and the alternative is explicitly chosen in that bean archive.

In other words, you must select an alternative in the same module of the class that 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 choice only works for the in in witch module, the alternative is declared in beans.xml , the same does not apply to EJB. So your alternative to D , (being @Stateless ) is valid for the whole application.

+6
source

Since CDI 1.1. you can use @Priority so that your alternative is found in a global context - see here Enabling Dependencies and Programmatically Searching

And if you use @Priority, you do not need to declare an alternative in beans.xml - see here Using Alternatives in CDI Applications

+2
source

Source: https://habr.com/ru/post/1489064/


All Articles