Class loader issues in OSGi | Third-party libs using the Thread context

Issue

When you use third-party libraries in an OSGi bundle, you get class loading issues such as the following:

Requested factory mypackage.FooBar cannot be located. Classloader =java.net.URLClassLoader@6aa8d01c

Note: This error is just an example error message. The issue is that classes loaded by third-party libraries aren't found, even though the corresponding class is definitely imported.

Real-life example

Apache Axis2 could throw the following stacktrace for no reason:

18.02.2010 17:04:30.153 *INFO* [10.43.97.19 [1266509048609] POST /path/to/servlet HTTP/1.1] 
org.apache.axis2.transport.http.HTTPSender Unable to sendViaPost to url[xy] org.apache.axis2.AxisFault: 
Requested factory com.ctc.wstx.stax.WstxOutputFactory cannot be located.  
Classloader =java.net.URLClassLoader@6aa8d01c
 at org.apache.axis2.AxisFault.makeFault(AxisFault.java:430)
 at org.apache.axis2.transport.http.AxisRequestEntity.writeRequest(AxisRequestEntity.java:96)
 at org.apache.commons.httpclient.methods.EntityEnclosingMethod.writeRequestBody(EntityEnclosingMethod.java:499)
        ...

Solution

The way that third-party libraries load their classes is out of your control. In most cases it's fine, if the third-party library uses the normal classloader from the bundle. But sometimes a library, like Apache Axis2, could try to load a class like the following:
Thread.currentThread().getContextClassLoader().loadClass("mypackage.FooBar");
By default, the Thread context class loader is not aware of OSGi and thus doesn't see any of the classes imported in the bundle. That's why loading the class fails.

In your code, before the third-party code is executed, you can tell the current thread to use the class loader from the bundle. Do this temporarily for the third-party code that doesn't load some classes:

ClassLoader tccl = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
try {
  // execute 3rd party code
} finally {
  Thread.currentThread().setContextClassLoader(tccl);
}

 

Applies to

CQ 5.x, AEM6.x

Adobe

Pomoc dostępna szybciej i łatwiej

Nowy użytkownik?