Return of an Unexpected Class Type After a
Lookup Operation
A lookup operation of an object from a server-side client (application, service, library) returns an unexpected object type.

Coding Example:
Context jndiCtx = new InitialContext();
Object object = jndiCtx.lookup(“objectName”);
LookedUpObjectInterface result = (LookedUpObjectInterface) PortableRemoteObject.narrow (object, LookedUpObjectInterface.class);
Throws:
java.lang.ClassCastException: com.sap.engine.interfaces.cross.ObjectReferenceImpl
at com.sap.engine.services.cross.PortableRemoteObjectContainer.narrow(PortableRemoteObjectContainer.java:154)
at com.sap.engine.system.PortableRemoteObjectProxy.narrow(PortableRemoteObjectProxy.java:24) ...............
or:
java.lang.ClassCastException: com.sap.engine.services.naming.persistent.UnsatisfiedReferenceImpl
at com.sap.engine.services.cross.PortableRemoteObjectContainer.narrow(PortableRemoteObjectContainer.java:154)
at com.sap.engine.system.PortableRemoteObjectProxy.narrow(PortableRemoteObjectProxy.java:24) ...............
|
Scenario Type: |
Error analysis |
|
NetWeaver Component: |
J2EE Engine |
|
Validity: |
J2EE Engine 6.40 and higher |
-
-
The client does not have a class loader reference to the component that has bound the object that the client tries to look up.
Check
if the client has a class loader reference to the component that has bound the
object. In this case, the client class loader will be able to load the
looked-up object. Otherwise, put a class loader reference. For more
information, see
Registering
References.
The
client is a server-side component (usually a library), which has such a class
loader reference and provides the possibility to use the lookup functionality
to other components.
The class loading mechanism in a lookup operation works this way:
If the client is an application, the application class loader is used to load the looked-up object. If it fails, the contextClassLoader from the currentThread is used. If it also fails, a com.sap.engine.interfaces.cross.ObjectReference or com.sap.engine.interfaces.cross.UnsatisfiedReference instance is returned as a result of the lookup operation.
If the client is not an application, only the contextClassLoader is used.
The tricky thing here is how the "client" is defined.
The client is the component which initiates the lookup operation. It could be a service (A), which in its start method looks up the interface of another service (B) in order to use its business methods. In this case a class loader reference from service A to service B will be enough for the correct performance of the lookup operation.
The other case is when service A calls a method of the looked-up interface of service B. In this method service B makes several operations in order to return some result. Imagine that service B needs to look-up another service (C) in order to get some data from it. For this lookup operation a reference from service B to service C is put. But this appears to be not enough.
When service A is started the contextClassLoader field of the thread keeps the class loader of this service (class loader CA). Class loader CA has a class loader reference to the class loader of the service B (class loader CB). When the call reaches the lookup operation of service B, the object that is an instance of a class from service B is successfully loaded because CA has reference to CB. Back in the start method of server A, a method of the looked-up object (a class from service B) is invoked. This method makes another lookup operation. It looks-up an object bound from service C. This object will not be loaded successfully, because the context class loader of the thread is still CA and it does not have a reference to CC (the class loader of the service C). So the result will be an object from type ObjectReference or UnsatisfiedReference.
...
1. Put a reference from CA to CC. However, this might not be satisfactory, because service A does not know that service B in its business method will need to look-up service C. Later the implementation of service B could be changed and it could need to look-up another service instead of service C. Then all the components that use methods of service B should change the class loader reference from CA to another one.
2. Reset the value of the contextClassLoader field of the thread in the method of service B which makes the lookup operation. In the service B source code, just before making the lookup operation, the contextClassLoader is set instead of CA to CB. CB has a reference to CC, so the looked-up object will be properly loaded. After the result is returned the contextClassLoader should be set back to CA.
ClassLoader saveLoader = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
SomeObjectCast obj = (SomeObjectCast) context.lookup("nameToLookup");
} finally {
Thread.currentThread().setContextClassLoader(saveLoader);
} // it is important always to return the original context class loader after lookup has finished
-
