1/*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/* @test
25 * @bug 4227189
26 * @summary Ensure that class descriptor read, write hooks exist, are backwards
27 *          compatible, and work as advertised.
28 */
29
30import java.io.*;
31import java.util.*;
32
33class Foo implements Serializable {
34    private static final long serialVersionUID = 1L;
35    Short s = new Short((short) 1);
36    Integer i = new Integer(2);
37    Long l = new Long(3);
38
39    public boolean equals(Object obj) {
40        if (obj instanceof Foo) {
41            Foo ofoo = (Foo) obj;
42            return s.equals(ofoo.s) && i.equals(ofoo.i) && l.equals(ofoo.l);
43        }
44        return false;
45    }
46}
47
48class CustomOutputStream extends ObjectOutputStream {
49
50    boolean hookCalled = false;
51
52    CustomOutputStream(OutputStream out) throws IOException {
53        super(out);
54        useProtocolVersion(PROTOCOL_VERSION_2);
55    }
56
57    protected void writeClassDescriptor(ObjectStreamClass desc)
58        throws IOException
59    {
60        writeUTF(desc.getName());
61        hookCalled = true;
62    }
63}
64
65class CustomInputStream extends ObjectInputStream {
66
67    boolean hookCalled = false;
68
69    CustomInputStream(InputStream in) throws IOException {
70        super(in);
71    }
72
73    protected ObjectStreamClass readClassDescriptor()
74        throws IOException, ClassNotFoundException
75    {
76        hookCalled = true;
77        return ObjectStreamClass.lookup(Class.forName(readUTF()));
78    }
79}
80
81public class ClassDescHooks implements ObjectStreamConstants {
82    public static void main(String[] args) throws Exception {
83        ByteArrayOutputStream bout;
84        ByteArrayInputStream bin;
85        ObjectOutputStream oout;
86        ObjectInputStream oin;
87        FileInputStream fin;
88        File foof;
89        CustomOutputStream cout;
90        CustomInputStream cin;
91
92        // test for backwards compatibility
93        bout = new ByteArrayOutputStream();
94        foof = new File(System.getProperty("test.src", "."), "Foo.ser");
95        fin = new FileInputStream(foof);
96        try {
97            while (fin.available() > 0)
98                bout.write(fin.read());
99        } finally {
100            fin.close();
101        }
102        byte[] buf1 = bout.toByteArray();
103
104        bout = new ByteArrayOutputStream();
105        oout = new ObjectOutputStream(bout);
106        Foo foo = new Foo();
107        oout.writeObject(foo);
108        oout.flush();
109        byte[] buf2 = bout.toByteArray();
110
111        if (! Arrays.equals(buf1, buf2))
112            throw new Error("Incompatible stream format (write)");
113
114        Foo foocopy;
115        fin = new FileInputStream(foof);
116        try {
117            oin = new ObjectInputStream(fin);
118            foocopy = (Foo) oin.readObject();
119            if (! foo.equals(foocopy))
120                throw new Error("Incompatible stream format (read)");
121        } finally {
122            fin.close();
123        }
124
125        // make sure write hook not called when old protocol in use
126        bout = new ByteArrayOutputStream();
127        cout = new CustomOutputStream(bout);
128        cout.useProtocolVersion(PROTOCOL_VERSION_1);
129        cout.writeObject(foo);
130        if (cout.hookCalled)
131            throw new Error("write descriptor hook should not be called");
132
133        // write custom class descriptor representations
134        bout = new ByteArrayOutputStream();
135        cout = new CustomOutputStream(bout);
136        cout.writeObject(foo);
137        cout.flush();
138        bin = new ByteArrayInputStream(bout.toByteArray());
139        cin = new CustomInputStream(bin);
140        foocopy = (Foo) cin.readObject();
141        if (! cout.hookCalled)
142            throw new Error("write descriptor hook never called");
143        if (! cin.hookCalled)
144            throw new Error("read descriptor hook never called");
145        if (! foo.equals(foocopy))
146            throw new Error("serialization failed when hooks active");
147    }
148}
149