Ville Myrskyneva
Ville Myrskyneva

Reputation: 1640

How to get and cast JNDI object correctly in Liberty

I have a big problem on getting the correct instance or at least casting the instance I got with JNDI-lookup to correct interface at Web Sphere Liberty (16.0.0.4, running on Java 7, though using Oracle Java 1.8.0_45 in the back, developing on Eclipse Neon.2).

When I start the server and the ear containing the EJB, I get the following notification into the log:

The server is binding the xxx.interfaces.MyLocal interface of the MyEJB enterprise bean in the xxx-ejb.jar module of the xxx-ear application. The binding location is: java:global/xxx/MyEJB!xxx.interfaces.MyLocal

Then I have a web application (ear) which has a service provider (with @Produces) for the previously started ejb-service, which will provide the JNDI resource as injectable (@Inject) for the rest of the application (a bit tricky thing, the main idea is to allow to change the lookup location from configuration file + do some other stuff also). It seems to work correctly for all it is supposed to, but when getting the JNDI-resource, it kind of works but not correctly.

If I put the ejb part as a dependency into my web-module, I can inject it directly (@Inject MyLocal myEjb;).

As the injected resource I get an object with the signature: EJSMyLocal0SLMyEJB_a4549339@cc5d2cdd
with lookup I get an object with signature (at the same time as the inject): EJSMyLocal0SLMyEJB_a4549339@cdda36a7
(Not the same instance afaik, but the "type" is correct?)

The injected resource is correctly (automatically of course) cast on 'MyLocal' interface and is ok. When I try to check the resource got with JNDI, it does not qualify as an instance of 'MyLocal' nor as 'MyRemote'? Also the actual cast fails of course with ClassCastException. (MyRemote is basically the same as the MyLocal interface ... MyLocal extends MyRemote, both interfaces are accordingly annotated with @Local and @Remote)
The EJB looks like this at the time of testing...

@Stateless
@Named
@Default
@Local(MyLocal.class)
@Remote(MyRemote.class)
public class MyEJB implements MyLocal, MyRemote { ... }

I also tried to cast the JNDI resource like this.

InitialContext ic = new InitialContext();
Object lookedUpEjb = ic.lookup(lookup); // the 'java:global...' from log
MyRemote jndiEjb = (MyRemote) PortableRemoteObject.narrow(lookedUpEjb, MyRemote.class)
// Tried also casting/checking 'instanceof' to MyLocal...

No difference with that, the same ClassCastException occurs?!

I have the following features in server.xml

<featureManager>
    <feature>javaee-7.0</feature>
    <feature>ldapRegistry-3.0</feature>
    <feature>localConnector-1.0</feature>
    <feature>adminCenter-1.0</feature>
    <feature>wsSecurity-1.1</feature>
    <feature>ejbLite-3.2</feature>
    <feature>ejbRemote-3.2</feature>
    <feature>cdi-1.2</feature>
    <feature>jpa-2.1</feature>
    <feature>jsf-2.2</feature>
    <feature>jaxrs-2.0</feature>
    <feature>jaxws-2.2</feature>
</featureManager>

I found this documentation on the Liberty JNDI functionality: https://www.ibm.com/support/knowledgecenter/SSAW57_liberty/com.ibm.websphere.wlp.nd.multiplatform.doc/ae/twlp_ejb_remote.html

I can't see where I go wrong. How do I cast that object from JNDI lookup to MyLocal or MyRemote interfaces?

---- Note ----
Using the @EJB annotation is not an option (it works though), since it will be hard coded reference to the resource. I want it to be optional though, thus JNDI lookup. @EJB will cause the app to crash when the resource is not available.

Upvotes: 0

Views: 1380

Answers (1)

Tracy
Tracy

Reputation: 1073

The problem is that each application has a different ClassLoader and the object that has been bound into JNDI was loaded with the ClassLoader of the application that defined the EJB.

This should not be an issue for Remote EJB interfaces as the ORB should have taken care of this for you. On a remote call that returns such an object, the ORB will serialize the object (from the target ClassLoader) and then deserialize using the client ClassLoader. For a lookup like this, the PortableRemoteObject.narrow should also take care of this. The failure here appears to just be a bug in the ORB.

In order to support cross application access to Local EJB interfaces, either the Local EJB interface needs to be moved to a shared library, that is used by both applications, or both applications configured to use a single global ClassLoader. See this link for more information about using Local EJB interfaces across applications: Correct way to lookup local EJB in websphere - Getting ClassCastException (Note: this link is discussing traditional WebSphere, but the issue is the same with Liberty, as is the resolution to use a shared library for the interface).

Upvotes: 2

Related Questions