Start of Content Area

Background documentation Return of an Unexpected Class Type After a Lookup Operation  Locate the document in its SAP Library structure

Problem Description

A lookup operation of an object from a server-side client (application, service, library) returns an unexpected object type.

Example

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

Decision Roadmap

Prerequisites

-

Main Tools

-

Analysis

Possible reason 1

The client does not have a class loader reference to the component that has bound the object that the client tries to look up.

Solution 1

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.

Possible reason 2

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.

Solution 2

...

       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.

Example:

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

Additional Information

-

 

End of Content Area