I have a legacy EJB application that was originally developed in Java 1.6 and deployed on WebSphere 8.5 more than a decade ago. Recently, I upgraded the Java version to 1.8 and the WebSphere version to 9.0.5. The application works fine.
However, I'm encountering a peculiar issue related to a specific XDoclet-based stateless session bean. This bean is annotated with @ejb.util generate = "physical".
The issue occurs when the batch job starts first and creates the bean, and then the application attempts to use the bean. I get the following exception:
Caused by: java.lang.ClassCastException: org.omg.stub.javax.ejb._EJBHome_Stub incompatible with com.xxx.common.reference.interfaces.ReferenceDataBeanHome
If the application creates the bean first and then the batch job uses it, everything works as expected.
XDoclet Generated Code:
The narrowing code is already generated by the XDoclet, we can't edit the code
private static Object lookupHome(java.util.Hashtable environment, String jndiName, Class narrowTo) throws javax.naming.NamingException {
// Obtain initial context
javax.naming.InitialContext initialContext = new javax.naming.InitialContext(environment);
try {
Object objRef = initialContext.lookup(jndiName);
// only narrow if necessary
if (narrowTo.isInstance(java.rmi.Remote.class))
return javax.rmi.PortableRemoteObject.narrow(objRef, narrowTo);
else
return objRef;
} finally {
initialContext.close();
}
}
What I tried:
I have changed the @ejb.util generate = "logical".
based on the IBM WebSphere suggestion but the Batch job starts to fail if starts after the application creates the Bean
Environment:
- Java Version: 1.8
- WebSphere Version: 9.0.5
Specifics:
- The issue is tied to the usage of
@ejb.util generate = "physical"
with XDoclet. - The exception occurs when the batch job initializes the bean before the application.
Question:
- What could be causing this ClassCastException when the batch job starts first?
- How can I ensure compatibility in both scenarios: when the application initializes the bean first and when the batch job does? Any insights, suggestions, or solutions would be greatly appreciated. Thank you!
The code that is failing with the ClassCastException is not calling
PortableRemoteObject.narrow()
. Anytime a remote EJB is looked up in naming it should perform aPortableRemoteObject.narrow
.Often, code will work without the narrow because the ORB will attempt to narrow automatically, but this does not always work, depending on the classpath of the client at the time of the lookup. If the first lookup does not have the stub on the classpath, then you will get the EJBHome stub. Unfortuntely, this can then end up cached in Naming, which may effect other clients as well. Always performing the narrow avoids this issue.
Since the JNDI lookup is returning an
_EJBHome_Stub
, this means the JNDI name is for a remote home and that the thread context classloader does not have access to the target class,ReferenceDataBeanHome
. Since the ORB is unable to load_ReferenceDataBeanHome_Stub
, then it will return_EJBHome_Stub
instead, which must be narrowed.What is especially curious with this scenario is that the code does contain a call to narrow, but it is not being called, suggesting that
narrowTo.isInstance(java.rmi.Remote.class)
is returningfalse
. Since the home being looked up is a remote home, thenarrowTo
class should implementjavax.ejb.EJBHome
, which extendsjava.rmi.Remote
and therefore this method should returntrue
and the narrow should be performed.I recommend checking the following:
java.rmi.Remote
class is not packaged in the application or otherwise included on the application classpath. Basically, need to determine why thenarrowTo
parameter onlookupHome
is failing theisInstance
check. This could happen ifjava.rmi.Remote
is loaded by two different classloaders.Determining why
isInstance
is returning false is the best solution. Alternatively, you could make sure the_ReferenceDataBeanHome_Stub
class is packaged with the batch application, and that may allow the ORB to proactively narrow; however this seems like a workaround.