0
votes

I'm developing a Java EE 6 application that must work in both JBoss WildFly 8.2.0 and IBM WAS 8.5.5.4 with the same EAR package.

The application structure is pretty simple. It basically follows the below one:

EAR
|__ /lib/
|____|__ API.jar
|____|__ IMPL.jar
|
|__ EJB.jar
|__ WebConsole.war
|____|__/lib
|_______|__C.jar

In the EJB module, I have a single @Stateless Session bean that tries to @Inject a POJO.
The particularity here is that the POJO implements an interface that resides in [API.jar] , but the implementation resides in [IMPL.jar].

Furthermore, the POJO Implementation is annotated with our own qualifier, namely @ServiceProvider. , that it's just defined as:

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD,ElementType.PARAMETER})
public @interface ServiceProvider {

}

The EJB looks like this ( just the relevant code shown ):

@Stateless
@Local(SecurityServiceLocal.class)
public class SecurityService implements SecurityServiceLocal {

    @Inject @ServiceProvider
    IServiceProvider serviceProvider;
    ...
}

The POJO Interface ( inside API.jar ) looks like this:

public interface IServiceProvider {

    public String sayHello();
}

The POJO Implementation ( inside IMPL.jar ) looks like this:

@Named
@ServiceProvider
public class ServiceProviderImpl implements IServiceProvider, Serializable {

   private static final long serialVersionUID = -1L;

   @Override
   public String sayHello() {
       return "Hello!";
   }

Both [API.jar], [IMPL.jar] and even [EJB.jar] have an empty [/META-INF/beans.xml] to enable CDI.

A Factory using @Produces is also available in [IMPL.jar] , as shown below:

public class ServiceFactory {

    @Produces IServiceProvider getServiceProvider(@ServiceProvider IServiceProvider serviceProvider) {
        return serviceProvider;
    }
}

And last but not least, the [EJB.jar] has a reference to both [API.jar] and [IMPL.jar] in the /META-INF/MANIFEST.MF Class-Path attribute.


Now, when running this sample application in WildFly 8.2.0.Final, everything works as expected. An implementation of IServiceProvider annotated with @ServiceProvider is injected into the EJB.

Or in other words, the POJO in IMPL.jar implementing the interface in API.jar is injected into the Stateless Session bean in EJB.jar

However, when deploying the same application in IBM WebSphere 8.5.5.4, the injection fails with the following message during STARTUP:

javax.enterprise.inject.UnsatisfiedResolutionException: 
Api type [dummy.IServiceProvider] is not found with the qualifiers 
Qualifiers: [@dummy.qualifier.ServiceProvider()] for injection into Field Injection Point, field :  dummy.IServiceProvider dummy.securityplugin.service.SecurityService.serviceProvider, 
Bean Owner : [WSEjbBean [businessLocals=[interface dummy.securityplugin.service.SecurityServiceLocal], 
ejbName=SecurityService-975208151,Name:null,WebBeans Type:ENTERPRISE,
API Types:    [dummy.securityplugin.service.SecurityServiceLocal,java.lang.Object],
Qualifiers:[javax.enterprise.inject.Any,javax.enterprise.inject.Default]]
InjectionType   :  [interface dummy.IServiceProvider]
Annotated    :  [Annotated Field,Base Type : interface dummy.IServiceProvider,
Type Closures : [class java.lang.Object, interface dummy.IServiceProvider],
Annotations : [@dummy.qualifier.ServiceProvider(), @javax.inject.Inject()],
Java Member Name : serviceProvider]
Qualifiers   :  [[@dummy.qualifier.ServiceProvider()]]

The IBM Knowledge Center has a link that gives some insights of this type of exception :

http://www-01.ibm.com/support/knowledgecenter/SSD28V_8.5.5/com.ibm.websphere.nd.doc/ae/tweb_troubleshoot_cdi.html

However, to my understanding, everything is configured correctly ( it runs in WildFly 8 !! ).

Finally, I try something else: I MOVE the POJO implementation FROM [IMPL.jar] to [EJB.jar] ... and this time the Injection WORKS as expected in WebSphere 8.5.5.4

So it looks like if the POJO class to be injected in the EJB resides in the SAME ejb module, there is no issue at all.

However, in our final code structure, we MUST have the interfaces and implementations in [API.jar] and [IMPL.jar] respectively.

Therefore, the final question : What I am doing wrong ? Does IBM WebSphere 8.5.5.4 ( presumably other 8.x versions as well ) has some kind of bug here ? I need to recall, that the EJB module references both API and IMPL jars in the Class-Path Manifest attribute.

Help on this topic would be greatly appreciated ... Thanks !!!

1

1 Answers

1
votes

Eventually I found the root cause. The culprit was the application.xml

As I'm using Maven for generating the EAR package with the maven-ear-plugin, it turns out that, if we don't clearly specify the Java EE version as 6 , the default application.xml is targeted for old J2EE 1.3 systems.

WildFly 8 seems to ignore this, and everything works as expected. However, in WebSphere 8.x , if the application.xml does not specify version="6" , the Classpath settings are completely messed up.

In other words, the maven-ear-plugin must include the <version>6</version> tag as shown below:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-ear-plugin</artifactId>
    <version>2.7</version>
    <configuration>            
        <version>6</version>
    ...

To correctly generate the right version for application.xml:

<xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                             http://java.sun.com/xml/ns/javaee/application_6.xsd" 
         version="6">