Wednesday, May 30, 2012

try/with/resource context class loaders


For various reasons I seem to end up writing a lot of code that fiddles with the context class loader in order to get non-module code running in the OSGi environment that JDeveloper runs in. This leads to a whole bunch of code that looks like this:

 public void doSomething() {

       ClassLoader context = Thread.currentThread().getContextClassLoader();

       try {
           Thread.currentThread().setContextClassLoader(Example.class.getClassLoader());

           // Class class that required the context class loader
           Endpoint.publish(null, null);            
       }
       finally {
           Thread.currentThread().setContextClassLoader(context);

       }  
  }


Now it occurred to me that the try/with/resources feature in JDK 7 isn't just for the nasty things in life, well resources, you can use it for any operation that might previously used a try/finally for.



   public void doSomething() {

       try (CloseableContext c = contextClassLoader(Example.class)) {

           // Class class that required the context class loader
           Endpoint.publish(null, null);            
       }
   }


It would have been nice to just call the method an not to allocate any variables as in the following example but it isn't allowable in the spec.


   public void doSomething() {

       try (contextClassLoader(Example.class)) { // Compilation errors

           // Class class that required the context class loader
           Endpoint.publish(null, null);            
       }
   }


Still the implementation of this is rather trivial and does still tidy up the original code. The only wrinkle is the  need to have a public class/ interface subtype of AutoCloseable so that we can narrow the throws clause on the close() operation. If you don't do this then the original code has to deal with "throws Exception".



   public static CloseableContext contextClassLoader(Class loader) {
       return contextClassLoader(loader.getClassLoader());
   }

   public static CloseableContext contextClassLoader(ClassLoader loader) {
       final Thread currentThread = Thread.currentThread();
       final ClassLoader ocl = currentThread.getContextClassLoader();
       currentThread.setContextClassLoader(loader);
       return new CloseableContext(currentThread, ocl);
   }

   public static class CloseableContext implements AutoCloseable {
       private Thread _currentThread;
       private ClassLoader _ocl;

       private CloseableContext(Thread currentThread, ClassLoader ocl) {
           this._currentThread = currentThread;
           this._ocl = ocl;
       }

       @Override
       public void close() {
           this._currentThread.setContextClassLoader(this._ocl);
       }
   }

1 comment:

Unknown said...

Nice example, thanks.
I agree that that a syntax without var name in the try { } block would be useful.

Since I do a lot of AutoCloseable wrappers too,
I have a common no-exception AutoCloseable intf:

interface Closeable extends AutoCloseable {

void close();
}


The example could be re-implemented:

public static Closeable contextClassLoader(ClassLoader loader) {

final Thread currentThread = Thread.currentThread();
final ClassLoader oldCL = currentThread.getContextClassLoader();
currentThread.setContextClassLoader(loader);
return new Closeable() {

public void close() {
currentThread.setContextClassLoader(oldCL);
}
}
}