1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.io.input; 18 19 import java.io.IOException; 20 import java.io.InputStream; 21 import java.io.ObjectInputStream; 22 import java.io.ObjectStreamClass; 23 import java.io.StreamCorruptedException; 24 import java.lang.reflect.Proxy; 25 26 /** 27 * A special ObjectInputStream that loads a class based on a specified 28 * {@link ClassLoader} rather than the system default. 29 * <p> 30 * This is useful in dynamic container environments. 31 * </p> 32 * 33 * @since 1.1 34 */ 35 public class ClassLoaderObjectInputStream extends ObjectInputStream { 36 37 /** The class loader to use. */ 38 private final ClassLoader classLoader; 39 40 /** 41 * Constructs a new ClassLoaderObjectInputStream. 42 * 43 * @param classLoader the ClassLoader from which classes should be loaded 44 * @param inputStream the InputStream to work on 45 * @throws IOException in case of an I/O error 46 * @throws StreamCorruptedException if the stream is corrupted 47 */ 48 public ClassLoaderObjectInputStream( 49 final ClassLoader classLoader, final InputStream inputStream) 50 throws IOException, StreamCorruptedException { 51 super(inputStream); 52 this.classLoader = classLoader; 53 } 54 55 /** 56 * Resolve a class specified by the descriptor using the 57 * specified ClassLoader or the super ClassLoader. 58 * 59 * @param objectStreamClass descriptor of the class 60 * @return the Class object described by the ObjectStreamClass 61 * @throws IOException in case of an I/O error 62 * @throws ClassNotFoundException if the Class cannot be found 63 */ 64 @Override 65 protected Class<?> resolveClass(final ObjectStreamClass objectStreamClass) 66 throws IOException, ClassNotFoundException { 67 68 try { 69 return Class.forName(objectStreamClass.getName(), false, classLoader); 70 } catch (final ClassNotFoundException cnfe) { 71 // delegate to super class loader which can resolve primitives 72 return super.resolveClass(objectStreamClass); 73 } 74 } 75 76 /** 77 * Create a proxy class that implements the specified interfaces using 78 * the specified ClassLoader or the super ClassLoader. 79 * 80 * @param interfaces the interfaces to implement 81 * @return a proxy class implementing the interfaces 82 * @throws IOException in case of an I/O error 83 * @throws ClassNotFoundException if the Class cannot be found 84 * @see java.io.ObjectInputStream#resolveProxyClass(String[]) 85 * @since 2.1 86 */ 87 @Override 88 protected Class<?> resolveProxyClass(final String[] interfaces) throws IOException, 89 ClassNotFoundException { 90 final Class<?>[] interfaceClasses = new Class[interfaces.length]; 91 for (int i = 0; i < interfaces.length; i++) { 92 interfaceClasses[i] = Class.forName(interfaces[i], false, classLoader); 93 } 94 try { 95 return Proxy.getProxyClass(classLoader, interfaceClasses); 96 } catch (final IllegalArgumentException e) { 97 return super.resolveProxyClass(interfaces); 98 } 99 } 100 101 }