1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2010 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.util.proxy;
17
18import java.io.IOException;
19import java.io.InputStream;
20import java.io.ObjectInputStream;
21import java.io.ObjectStreamClass;
22
23/**
24 * An input stream class which knows how to deserialize proxies created via {@link ProxyFactory} and
25 * serializedo via a {@link ProxyObjectOutputStream}. It must be used when deserialising proxies created
26 * from a proxy factory configured with {@link ProxyFactory#useWriteReplace} set to false.
27 *
28 * @author Andrew Dinn
29 */
30public class ProxyObjectInputStream extends ObjectInputStream
31{
32    /**
33     * create an input stream which can be used to deserialize an object graph which includes proxies created
34     * using class ProxyFactory. the classloader used to resolve proxy superclass and interface names
35     * read from the input stream will default to the current thread's context class loader or the system
36     * classloader if the context class loader is null.
37     * @param in
38     * @throws java.io.StreamCorruptedException whenever ObjectInputStream would also do so
39     * @throws	IOException whenever ObjectInputStream would also do so
40     * @throws	SecurityException whenever ObjectInputStream would also do so
41     * @throws NullPointerException if in is null
42     */
43    public ProxyObjectInputStream(InputStream in) throws IOException
44    {
45        super(in);
46        loader = Thread.currentThread().getContextClassLoader();
47        if (loader == null) {
48            loader = ClassLoader.getSystemClassLoader();
49        }
50    }
51
52    /**
53     * Reset the loader to be
54     * @param loader
55     */
56    public void setClassLoader(ClassLoader loader)
57    {
58        if (loader != null) {
59            this.loader = loader;
60        } else {
61            loader = ClassLoader.getSystemClassLoader();
62        }
63    }
64
65    protected ObjectStreamClass readClassDescriptor() throws IOException, ClassNotFoundException {
66        boolean isProxy = readBoolean();
67        if (isProxy) {
68            String name = (String)readObject();
69            Class superClass = loader.loadClass(name);
70            int length = readInt();
71            Class[] interfaces = new Class[length];
72            for (int i = 0; i < length; i++) {
73                name = (String)readObject();
74                interfaces[i] = loader.loadClass(name);
75            }
76            length = readInt();
77            byte[] signature = new byte[length];
78            read(signature);
79            ProxyFactory factory = new ProxyFactory();
80            // we must always use the cache and never use writeReplace when using
81            // ProxyObjectOutputStream and ProxyObjectInputStream
82            factory.setUseCache(true);
83            factory.setUseWriteReplace(false);
84            factory.setSuperclass(superClass);
85            factory.setInterfaces(interfaces);
86            Class proxyClass = factory.createClass(signature);
87            return ObjectStreamClass.lookup(proxyClass);
88        } else {
89            return super.readClassDescriptor();
90        }
91    }
92
93    /**
94     * the loader to use to resolve classes for proxy superclass and interface names read
95     * from the stream. defaults to the context class loader of the thread which creates
96     * the input stream or the system class loader if the context class loader is null.
97     */
98    private ClassLoader loader;
99}