webspherewebsphere-liberty

How can I use same, single class loader for every WAR application packaged in my EAR application?


I'm trying to migrate legacy application from WAS 9.0.5 to Websphere Liberty which is structured as follows:

EarApplication.ear
          |--> META-INF
                   |-->application.xml
          |--> WebApplication1.war
                 |---> META-INF 
                          |--> MANIFEST
                 |----->WEB-INF 
                          |--> classes
                          |--> lib 
                                 |--> WebApplication1Client.jar
                                 |--> WebApplication2Client.jar
                                 |--> Other libs
          |--> WebApplication2.war
                 |---> META-INF 
                          |--> MANIFEST
                 |----->WEB-INF 
                          |--> classes
                          |--> lib 
                                 |--> WebApplication2Client.jar
                                 |--> Other libs

WebApplication1Client.war contains following class (jax-rs definition):

@Path("a")
public interface A {
    @GET
    @PATH("a-method")
    AB getA();

    class AB implements Serializable {
    ...    
    }
}

WebApplication1.war contains following class:

@Steteless
@Local(A.class)
public AImpl implements A {
    
    @EJB
    private B b;

    @Override
    public AB getA(){
        BB bb = b.getB();
        return new getABFromBB(bb);
    }

    private AB getABFromBB(BB bb){
    ...
    }
}

WebApplication2Client.war contains following class (jax-rs definition):

@Path("b")
public interface B {
    @GET
    @PATH("b-method")
    BB getB();

    class BB implements Serializable {
    ...    
    } 

}

WebApplication2.war contains following class:

@Steteless
@Local(B.class)
public BImpl implements B {
    
    @Override
    public BB getB(){
        return new BB();
    }

}

Due to fact that applications WebApplication1.war and WebApplication2.war are loaded by different class loaders, I get following exception:

CWOWB1000E: A CDI error has occurred: CWNEN0074E: THE EJSLocal_B_64388ed6 type of object instance obtained for the java:comp/env/AImpl/b reference is incompatible with the type of the B AImpl member.

Same problem in WAS 9.0.5 could be solved by checking option 'Single class loader for application' on application level, like described here https://www.ibm.com/docs/en/was-nd/9.0.5?topic=loading-configuring-application-class-loaders (point 5).

Unfortunately documentation of Websphere Liberty do not mention any options for this.

My server.xml looks as follows:

<server>

   <features>
       <feature>javaee-7.0</feature>
   </features>

   <applicationManager autoExpand="true"/>

   <enterpriseApplication location="EarApplication.ear"/>

</server>

Is there similar option for this configuration in Websphere Liberty like in WAS?


Solution

  • Your check of the documentation was correct - Liberty does not offer the "single class loader for application" setting that was present in WebSphere traditional.

    For situations like this, a small restructuring of the application would be your best solution. Classes that are required by multiple modules in the same application would be best placed in a /lib directory within the EAR (using the library-directory mechanism of Java/Jakarta EE), which makes them available to all of the WARs through the EAR's class loader. This packaging setup provides improved logical consistency, as classes common to both modules are now in a physical location common to both modules, and it also makes your app more portable, since that packaging style is more consistent with the Java/Jakarta EE specification (the single class loader for the entire application is a WebSphere traditional setting that is not required by the spec).