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 */ 017package org.apache.commons.io.input; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.ObjectInputStream; 022import java.io.ObjectStreamClass; 023import java.io.StreamCorruptedException; 024import 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 * @since 1.1 033 */ 034public class ClassLoaderObjectInputStream extends ObjectInputStream { 035 036 /** The class loader to use. */ 037 private final ClassLoader classLoader; 038 039 /** 040 * Constructs a new ClassLoaderObjectInputStream. 041 * 042 * @param classLoader the ClassLoader from which classes should be loaded 043 * @param inputStream the InputStream to work on 044 * @throws IOException in case of an I/O error 045 * @throws StreamCorruptedException if the stream is corrupted 046 */ 047 public ClassLoaderObjectInputStream( 048 final ClassLoader classLoader, final InputStream inputStream) 049 throws IOException, StreamCorruptedException { 050 super(inputStream); 051 this.classLoader = classLoader; 052 } 053 054 /** 055 * Resolve a class specified by the descriptor using the 056 * specified ClassLoader or the super ClassLoader. 057 * 058 * @param objectStreamClass descriptor of the class 059 * @return the Class object described by the ObjectStreamClass 060 * @throws IOException in case of an I/O error 061 * @throws ClassNotFoundException if the Class cannot be found 062 */ 063 @Override 064 protected Class<?> resolveClass(final ObjectStreamClass objectStreamClass) 065 throws IOException, ClassNotFoundException { 066 067 try { 068 return Class.forName(objectStreamClass.getName(), false, classLoader); 069 } catch (final ClassNotFoundException cnfe) { 070 // delegate to super class loader which can resolve primitives 071 return super.resolveClass(objectStreamClass); 072 } 073 } 074 075 /** 076 * Create a proxy class that implements the specified interfaces using 077 * the specified ClassLoader or the super ClassLoader. 078 * 079 * @param interfaces the interfaces to implement 080 * @return a proxy class implementing the interfaces 081 * @throws IOException in case of an I/O error 082 * @throws ClassNotFoundException if the Class cannot be found 083 * @see java.io.ObjectInputStream#resolveProxyClass(java.lang.String[]) 084 * @since 2.1 085 */ 086 @Override 087 protected Class<?> resolveProxyClass(final String[] interfaces) throws IOException, 088 ClassNotFoundException { 089 final Class<?>[] interfaceClasses = new Class[interfaces.length]; 090 for (int i = 0; i < interfaces.length; i++) { 091 interfaceClasses[i] = Class.forName(interfaces[i], false, classLoader); 092 } 093 try { 094 return Proxy.getProxyClass(classLoader, interfaceClasses); 095 } catch (final IllegalArgumentException e) { 096 return super.resolveProxyClass(interfaces); 097 } 098 } 099 100}