1/*
2 * Copyright (c) 1998, 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 4140729
26 * @summary Verify that writeReplace & readResolve are called by serialization.
27 *          readResolve is used to maintain the invariant that the enums
28 *          of TypeSafeEnum are singletons.
29 */
30import java.io.*;
31
32public class TypeSafeEnum implements Serializable, ObjectInputValidation {
33    private static int numWriteObject = 0;
34    private static int numReadObject = 0;
35
36
37    private String value;
38    private TypeSafeEnum(String value) {
39        this.value = value;
40    }
41
42    public static final TypeSafeEnum FIRST = new TypeSafeEnum("First");
43    public static final TypeSafeEnum SECOND = new TypeSafeEnum("Second");
44    public static final TypeSafeEnum THIRD = new TypeSafeEnum("Third");
45    static int numReadResolve = 0;
46    static int numWriteReplace = 0;
47    static boolean verbose = false;
48
49
50    private Object writeReplace() throws IOException {
51        numWriteReplace++;
52        if (verbose) {
53            System.out.println("TypeSafeEnum.writeReplace() " +
54                               this.toString());
55        }
56        return this;
57    }
58
59    private Object readResolve() throws IOException {
60        numReadResolve++;
61        if (verbose) {
62            System.out.println("readResolve called on " + this.toString());
63        }
64        if (value.equals(FIRST.value)) {
65            return FIRST;
66        } else if (value.equals(SECOND.value)) {
67            return SECOND;
68        } else if (value.equals(THIRD.value)) {
69            return THIRD;
70        } else {
71            //unknown type safe enum
72            return this;
73        }
74    }
75
76    private void readObject(ObjectInputStream in)
77        throws IOException, ClassNotFoundException
78    {
79        numReadObject++;
80        in.defaultReadObject();
81        if (verbose) {
82            System.out.println("TypeSafeEnum.readObject() " + this.toString());
83        }
84        if (value == null) {
85            in.registerValidation(this, 0);
86        }
87    }
88
89    public void validateObject() throws InvalidObjectException {
90        // only top level case has null for value, validate.
91        if (numWriteObject != 4) {
92            throw new Error("Expected 4 calls to writeObject, only " +
93                            numWriteObject + " made");
94        }
95        if (numReadObject != 4) {
96            throw new Error("Expected 4 calls to readObject, only " +
97                            numReadObject + " made");
98        }
99        if (numWriteReplace != 4) {
100            throw new Error("Expected 4 calls to writeReplace, only " +
101                            numWriteReplace + " made");
102        }
103        if (numReadResolve != 4) {
104            throw new Error("Expected 4 calls to readResolve, only " +
105                            numReadResolve + " made");
106        }
107    }
108
109    private void writeObject(ObjectOutputStream out) throws IOException
110    {
111        numWriteObject++;
112        out.defaultWriteObject();
113        if (verbose) {
114            System.out.println("TypeSafeEnum.writeObject() " +
115                               this.toString());
116        }
117    }
118
119    public String toString() {
120        return super.toString() + " value=" + value;
121    }
122
123    public static void main(String args[])
124        throws IOException, ClassNotFoundException
125    {
126        if (args.length > 0 && args[0].equals("-verbose"))
127            verbose = true;
128
129        TypeSafeEnum[] writeArray = new TypeSafeEnum[7];
130        writeArray[0] = FIRST;
131        writeArray[1] = SECOND;
132        writeArray[2] = THIRD;
133        writeArray[3] = FIRST;
134        writeArray[4] = SECOND;
135        writeArray[5] = THIRD;
136        writeArray[6] = new TypeSafeEnum("Third");
137
138        ByteArrayOutputStream baos = new ByteArrayOutputStream();
139        ObjectOutputStream os = new ObjectOutputStream(baos);
140        os.writeObject(writeArray);
141        os.close();
142
143        TypeSafeEnum[] readArray;
144        ObjectInputStream in =
145           new ObjectInputStream(new ByteArrayInputStream(baos.toByteArray()));
146        readArray = (TypeSafeEnum[])in.readObject();
147        in.close();
148
149        for (int i= 0; i < writeArray.length - 1 ; i++) {
150            if (writeArray[i] != readArray[i]) {
151                throw new Error("Serializa/deserialize did not preserve " +
152                                "singleton for " +
153                                readArray[i].toString() +
154                                " and " + writeArray[i].toString());
155            }
156        }
157   }
158};
159