ObjectInputStreamWithClassLoader.java |
/*************************************** * * * JBoss: The OpenSource J2EE WebOS * * * * Distributable under LGPL license. * * See terms of license at gnu.org. * * * ***************************************/ package org.jboss.remoting.loading; import java.io.IOException; import java.io.ObjectInputStream; import java.io.StreamCorruptedException; /** * ObjectInputStreamWithClassLoader * * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a> * @author <a href="mailto:tom@jboss.org">Tom Elrod</a> * @version $Revision: 1.1.14.1 $ */ public class ObjectInputStreamWithClassLoader extends ObjectInputStream { private ClassLoader cl; /** * Create an ObjectInputStream that reads from the specified InputStream. * The stream header containing the magic number and version number * are read from the stream and verified. This method will block * until the corresponding ObjectOutputStream has written and flushed the * header. * * @param in the underlying <code>InputStream</code> from which to read * @throws java.io.StreamCorruptedException * The version or magic number are * incorrect. * @throws java.io.IOException An exception occurred in the underlying stream. */ public ObjectInputStreamWithClassLoader(java.io.InputStream in, ClassLoader cl) throws IOException, StreamCorruptedException { super(in); this.cl = cl; } /** * Set the classloader that the stream will used when deserializing class. This will * allow plugging in of classloaders based on invocation context. * * @param cl */ public void setClassLoader(ClassLoader cl) { this.cl = cl; } /** * Gets the pluggable classloader that will be used for classloading when deserializing * objects. * * @return */ public ClassLoader getClassLoader() { return cl; } /** * Load the local class equivalent of the specified stream class description. * <p/> * Subclasses may implement this method to allow classes to be * fetched from an alternate source. * <p/> * The corresponding method in ObjectOutputStream is * annotateClass. This method will be invoked only once for each * unique class in the stream. This method can be implemented by * subclasses to use an alternate loading mechanism but must * return a Class object. Once returned, the serialVersionUID of the * class is compared to the serialVersionUID of the serialized class. * If there is a mismatch, the deserialization fails and an exception * is raised. <p> * <p/> * By default the class name is resolved relative to the class * that called readObject. <p> * <p/> * Will use the classloader explicitly set if it exists. If it does not exist, * will used its default classloader (that loader this instance).<p> * * @param v an instance of class ObjectStreamClass * @return a Class object corresponding to <code>v</code> * @throws java.io.IOException Any of the usual Input/Output exceptions. * @throws java.lang.ClassNotFoundException * If class of * a serialized object cannot be found. */ protected Class resolveClass(java.io.ObjectStreamClass v) throws java.io.IOException, ClassNotFoundException { if(cl == null) { return super.resolveClass(v); } else { return cl.loadClass(v.getName()); } } /** * Returns a proxy class that implements the interfaces named in a * proxy class descriptor; subclasses may implement this method to * read custom data from the stream along with the descriptors for * dynamic proxy classes, allowing them to use an alternate loading * mechanism for the interfaces and the proxy class. * <p/> * <p>This method is called exactly once for each unique proxy class * descriptor in the stream. * <p/> * <p>The corresponding method in <code>ObjectOutputStream</code> is * <code>annotateProxyClass</code>. For a given subclass of * <code>ObjectInputStream</code> that overrides this method, the * <code>annotateProxyClass</code> method in the corresponding * subclass of <code>ObjectOutputStream</code> must write any data or * objects read by this method. * <p/> * <p>The default implementation of this method in * <code>ObjectInputStream</code> returns the result of calling * <code>Proxy.getProxyClass</code> with the list of * <code>Class</code> objects for the interfaces that are named in * the <code>interfaces</code> parameter. The <code>Class</code> * object for each interface name <code>i</code> is the value * returned by calling * <pre> * Class.forName(i, false, loader) * </pre> * where <code>loader</code> is that of the first non-null class * loader up the execution stack, or <code>null</code> if no non-null * class loaders are on the stack (the same class loader choice used * by the <code>resolveClass</code> method). This same value of * <code>loader</code> is also the class loader passed to * <code>Proxy.getProxyClass</code>. If <code>Proxy.getProxyClass</code> * throws an <code>IllegalArgumentException</code>, * <code>resolveProxyClass</code> will throw a * <code>ClassNotFoundException</code> containing the * <code>IllegalArgumentException</code>. * * @return a proxy class for the specified interfaces * @param interfaces the list of interface names that were * deserialized in the proxy class descriptor * @throws java.io.IOException any exception thrown by the underlying * <code>InputStream</code> * @throws java.lang.ClassNotFoundException if the proxy class or any of the * named interfaces could not be found * @since 1.3 * @see java.io.ObjectOutputStream#annotateProxyClass(java.lang.Class) */ protected Class resolveProxyClass(String[] interfaces) throws java.io.IOException, ClassNotFoundException { if(cl == null) { return super.resolveProxyClass(interfaces); } else { Class[] classObjs = new Class[interfaces.length]; for(int i = 0; i < interfaces.length; i++) { classObjs[i] = cl.loadClass(interfaces[i]); } try { return java.lang.reflect.Proxy.getProxyClass(cl, classObjs); } catch(IllegalArgumentException e) { throw new ClassNotFoundException(null, e); } } } }
ObjectInputStreamWithClassLoader.java |