1/*
2 * Copyright (c) 1998, 2012, 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 4099013
26 * @summary Enable substitution of String and Array by ObjectStreams.
27 */
28
29import java.io.*;
30import java.lang.reflect.Array;
31
32class A implements Serializable {
33    String stringA;
34    String stringB;
35    String stringC;
36    String[] arrayOfString;
37
38    A() {
39        stringA = "hello";
40        stringB = "goodbye";
41        stringC = stringA;
42        arrayOfString = new String[2];
43        for (int i = 0; i < arrayOfString.length; i++)
44            arrayOfString[i] = new String("array element " + i);
45    }
46
47    void report() {
48            System.out.println("stringA = " + stringA);
49            System.out.println("stringB = " + stringB);
50            System.out.println("stringC = " + stringC);
51            System.out.println("length of arrayOfString = " +
52                               arrayOfString.length);
53            for (int i = 0; i < arrayOfString.length; i++)
54                System.out.println("arrayOfString[" + i + "]= " +
55                                   arrayOfString[i]);
56    }
57}
58
59class SubstituteObjectOutputStream extends ObjectOutputStream {
60    public int numStringsReplaced = 0;
61    public int numArraysCounted = 0;
62
63    public SubstituteObjectOutputStream(OutputStream out) throws IOException {
64        super(out);
65        enableReplaceObject(true);
66    }
67
68    protected Object replaceObject(Object obj) throws IOException {
69        if (obj instanceof String) {
70            numStringsReplaced++;
71            return obj + "_WriteReplaced";
72        }
73        if (obj.getClass().isArray()) {
74            Object[] array = (Object[]) obj;
75            /* Double the array.
76             * Initialize new array elements with original array. */
77            Class arrayComponentType = array.getClass().getComponentType();
78            Object[] newarray =
79                (Object[])Array.newInstance(arrayComponentType,
80                                            array.length * 2);
81            for (int i = 0; i < array.length; i++)
82                newarray[i] = array[i];
83            for (int ni = array.length; ni < 2* array.length; ni++)
84                newarray[ni] = array[ni - array.length];
85            numArraysCounted++;
86            obj = newarray;
87        }
88        return obj;
89    }
90}
91
92class SubstituteObjectInputStream extends ObjectInputStream {
93    public int numStringsReplaced = 0;
94    public int numArraysCounted = 0;
95
96    public SubstituteObjectInputStream(InputStream in) throws IOException {
97        super(in);
98        enableResolveObject(true);
99    }
100
101    protected Object resolveObject(Object obj) throws IOException {
102        if (obj instanceof String) {
103            numStringsReplaced++;
104            return obj + "_ReadResolved";
105        }
106        if (obj.getClass().isArray()) {
107            Object[] array = (Object[])obj;
108
109            /* Double the array.
110             * Initialize new array elements with original array. */
111            Class arrayComponentType = array.getClass().getComponentType();
112            Object[] newarray =
113                (Object[])Array.newInstance(arrayComponentType,
114                                            array.length * 2);
115            for (int i = 0; i < array.length; i++)
116                newarray[i] = array[i];
117            for (int ni = array.length; ni < 2* array.length; ni++)
118                newarray[ni] = array[ni - array.length];
119            numArraysCounted++;
120            obj = newarray;
121        }
122        return obj;
123    }
124}
125
126public class ReplaceStringArray {
127    public static void main(String args[]) throws IOException, ClassNotFoundException {
128        boolean verbose = false;
129        if (args.length >= 1 && args[0].compareTo("verbose") == 0)
130            verbose = true;
131
132
133        A a = new A();
134        if (verbose) {
135            System.out.println("Value of Class A");
136            a.report();
137            System.out.println("");
138        }
139
140
141        /* Serialize object a to bytestream. */
142        if (verbose) {
143            System.out.println("Serialize A to SubstituteObjectOutputStream");
144            System.out.println("");
145        }
146        ByteArrayOutputStream baos = new ByteArrayOutputStream();
147        SubstituteObjectOutputStream out =   new SubstituteObjectOutputStream(baos);
148        out.writeObject(a);
149        out.close();
150        a = null;
151
152        /* Validate that writeReplace called by SubstituteObjectOutputStream.*/
153        boolean expectedResult = (out.numStringsReplaced == 4);
154        if (!expectedResult)
155            throw new Error("Expected " + 4 + " strings to be replaced during serialization;" +
156                            " only " + out.numStringsReplaced + " strings were replaced.");
157        if (out.numArraysCounted != 1)
158            throw new Error("Expected 1 array during serialization; only " +
159                            out.numArraysCounted + " arrays");
160
161        if (verbose) {
162            System.out.println("DeSerialize A from SubstituteObjectInputStream");
163            System.out.println("");
164        }
165        SubstituteObjectInputStream in =
166            new SubstituteObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
167        a = (A)in.readObject();
168        in.close();
169
170        /* Validate that readResolve called by SubstituteObjectInputStream.*/
171        if (in.numStringsReplaced != 4)
172            throw new Error("Expected 4 strings to be resolved during deserialization;" +
173                            " only " + in.numStringsReplaced + " strings were resolved.");
174        if (in.numArraysCounted != 1)
175            throw new Error("Expected 1 array during deserialization; only " +
176                            out.numArraysCounted + " arrays");
177        if (a.arrayOfString.length != 8)
178            throw new Error("Expected a.arrayOfString.length to be 8, observed " +
179                            a.arrayOfString.length);
180        if (verbose) {
181            System.out.println("Value of Class A after serialize/deserialize with writeReplace/readResolve");
182            a.report();
183        }
184    }
185}
186