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 * https://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 try {
68 return Class.forName(objectStreamClass.getName(), false, classLoader);
69 } catch (final ClassNotFoundException cnfe) {
70 // delegate to super class loader which can resolve primitives
71 return super.resolveClass(objectStreamClass);
72 }
73 }
74
75 /**
76 * Create a proxy class that implements the specified interfaces using
77 * the specified ClassLoader or the super ClassLoader.
78 *
79 * @param interfaces the interfaces to implement
80 * @return a proxy class implementing the interfaces
81 * @throws IOException in case of an I/O error
82 * @throws ClassNotFoundException if the Class cannot be found
83 * @see ObjectInputStream#resolveProxyClass(String[])
84 * @since 2.1
85 */
86 @Override
87 protected Class<?> resolveProxyClass(final String[] interfaces) throws IOException,
88 ClassNotFoundException {
89 final Class<?>[] interfaceClasses = new Class[interfaces.length];
90 for (int i = 0; i < interfaces.length; i++) {
91 interfaceClasses[i] = Class.forName(interfaces[i], false, classLoader);
92 }
93 try {
94 return Proxy.getProxyClass(classLoader, interfaceClasses);
95 } catch (final IllegalArgumentException e) {
96 return super.resolveProxyClass(interfaces);
97 }
98 }
99
100 }