001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.io.input;
018
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.ObjectInputStream;
022 import java.io.ObjectStreamClass;
023 import java.io.StreamCorruptedException;
024 import java.lang.reflect.Proxy;
025
026 /**
027 * A special ObjectInputStream that loads a class based on a specified
028 * <code>ClassLoader</code> rather than the system default.
029 * <p>
030 * This is useful in dynamic container environments.
031 *
032 * @author Paul Hammant
033 * @version $Id: ClassLoaderObjectInputStream.java 1080933 2011-03-12 13:53:38Z niallp $
034 * @since Commons IO 1.1
035 */
036 public class ClassLoaderObjectInputStream extends ObjectInputStream {
037
038 /** The class loader to use. */
039 private final ClassLoader classLoader;
040
041 /**
042 * Constructs a new ClassLoaderObjectInputStream.
043 *
044 * @param classLoader the ClassLoader from which classes should be loaded
045 * @param inputStream the InputStream to work on
046 * @throws IOException in case of an I/O error
047 * @throws StreamCorruptedException if the stream is corrupted
048 */
049 public ClassLoaderObjectInputStream(
050 ClassLoader classLoader, InputStream inputStream)
051 throws IOException, StreamCorruptedException {
052 super(inputStream);
053 this.classLoader = classLoader;
054 }
055
056 /**
057 * Resolve a class specified by the descriptor using the
058 * specified ClassLoader or the super ClassLoader.
059 *
060 * @param objectStreamClass descriptor of the class
061 * @return the Class object described by the ObjectStreamClass
062 * @throws IOException in case of an I/O error
063 * @throws ClassNotFoundException if the Class cannot be found
064 */
065 @Override
066 protected Class<?> resolveClass(ObjectStreamClass objectStreamClass)
067 throws IOException, ClassNotFoundException {
068
069 Class<?> clazz = Class.forName(objectStreamClass.getName(), false, classLoader);
070
071 if (clazz != null) {
072 // the classloader knows of the class
073 return clazz;
074 } else {
075 // classloader knows not of class, let the super classloader do it
076 return super.resolveClass(objectStreamClass);
077 }
078 }
079
080 /**
081 * Create a proxy class that implements the specified interfaces using
082 * the specified ClassLoader or the super ClassLoader.
083 *
084 * @param interfaces the interfaces to implement
085 * @return a proxy class implementing the interfaces
086 * @throws IOException in case of an I/O error
087 * @throws ClassNotFoundException if the Class cannot be found
088 * @see java.io.ObjectInputStream#resolveProxyClass(java.lang.String[])
089 * @since Commons IO 2.1
090 */
091 @Override
092 protected Class<?> resolveProxyClass(String[] interfaces) throws IOException,
093 ClassNotFoundException {
094 Class<?>[] interfaceClasses = new Class[interfaces.length];
095 for (int i = 0; i < interfaces.length; i++) {
096 interfaceClasses[i] = Class.forName(interfaces[i], false, classLoader);
097 }
098 try {
099 return Proxy.getProxyClass(classLoader, interfaceClasses);
100 } catch (IllegalArgumentException e) {
101 return super.resolveProxyClass(interfaces);
102 }
103 }
104
105 }