Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Inject @Alternative with CDI from WAR into EJB Module

I want to let CDI "pick up" an Alternative Class as Implementation of an Interface.

While everything is bundles in a EAR the Alternative Implementation will be in the war file and the rest (Class injecting the Interfaces, the Interface, "Default" Implementation of the Interfaces) will be in the ejb jar.

Here some 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 {}

Setting the beans.xml in the war file did not help..

like image 269
Nick Russler Avatar asked Jan 13 '23 00:01

Nick Russler


1 Answers

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.

like image 159
Carlo Pellegrini Avatar answered Jan 16 '23 00:01

Carlo Pellegrini