1 /*
2  * Copyright (c) 2019, 2020, 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 /*
25  * @test
26  * @bug 8246774
27  * @summary Basic tests for writeReplace
28  * @run testng WriteReplaceTest
29  * @run testng/othervm/java.security.policy=empty_security.policy WriteReplaceTest
30  */
31 package test.java.io.Serializable.records;
32 
33 import java.io.ByteArrayInputStream;
34 import java.io.ByteArrayOutputStream;
35 import java.io.IOException;
36 import java.io.ObjectInputStream;
37 import java.io.ObjectOutputStream;
38 import java.io.Serializable;
39 import org.testng.annotations.DataProvider;
40 import org.testng.annotations.Test;
41 import static java.lang.System.out;
42 import static org.testng.Assert.assertEquals;
43 
44 public class WriteReplaceTest {
45 
46     record R1 () implements Serializable {
writeReplace()47         Object writeReplace() { return new Replacement(); }
48 
49         private static class Replacement implements Serializable {
readResolve()50             private Object readResolve() { return new R1(); }
51         }
52     }
53 
54     record R2 (int x, int y) implements Serializable {
writeReplace()55         Object writeReplace() { return new Ser(x, y); }
56 
57         private static class Ser implements Serializable {
58             private final int x;
59             private final int y;
Ser(int x, int y)60             Ser(int x, int y) { this.x = x; this.y = y; }
readResolve()61             private Object readResolve() { return new R2(x, y); }
62         }
63     }
64 
65     record R3 (R1 r1, R2 r2) implements Serializable { }
66 
67     record R4 (long l) implements Serializable {
writeReplace()68         Object writeReplace() { return new Replacement(l); }
69 
70         static class Replacement implements Serializable {
71             long l;
Replacement(long l)72             Replacement(long l) { this.l = l; }
73         }
74     }
75 
76     @DataProvider(name = "recordObjects")
recordObjects()77     public Object[][] recordObjects() {
78         return new Object[][] {
79             new Object[] { new R1(),                       R1.class             },
80             new Object[] { new R2(1, 2),                   R2.class             },
81             new Object[] { new R3(new R1(), new R2(3,4)),  R3.class             },
82             new Object[] { new R4(4L),                     R4.Replacement.class },
83         };
84     }
85 
86     @Test(dataProvider = "recordObjects")
testSerialize(Object objectToSerialize, Class<?> expectedType)87     public void testSerialize(Object objectToSerialize, Class<?> expectedType)
88         throws Exception
89     {
90         out.println("\n---");
91         out.println("serializing : " + objectToSerialize);
92         Object deserializedObj = serializeDeserialize(objectToSerialize);
93         out.println("deserialized: " + deserializedObj);
94         if (objectToSerialize.getClass().equals(expectedType))
95             assertEquals(deserializedObj, objectToSerialize);
96         else
97             assertEquals(deserializedObj.getClass(), expectedType);
98     }
99 
100     // -- null replacement
101 
102     record R10 () implements Serializable {
writeReplace()103         Object writeReplace() { return null; }
104     }
105 
106     @Test
testNull()107     public void testNull() throws Exception {
108         out.println("\n---");
109         Object objectToSerialize = new R10();
110         out.println("serializing : " + objectToSerialize);
111         Object deserializedObj = serializeDeserialize(objectToSerialize);
112         out.println("deserialized: " + deserializedObj);
113         assertEquals(deserializedObj, null);
114     }
115 
116     // --- infra
117 
serialize(T obj)118     static <T> byte[] serialize(T obj) throws IOException {
119         ByteArrayOutputStream baos = new ByteArrayOutputStream();
120         ObjectOutputStream oos = new ObjectOutputStream(baos);
121         oos.writeObject(obj);
122         oos.close();
123         return baos.toByteArray();
124     }
125 
126     @SuppressWarnings("unchecked")
deserialize(byte[] streamBytes)127     static <T> T deserialize(byte[] streamBytes)
128         throws IOException, ClassNotFoundException
129     {
130         ByteArrayInputStream bais = new ByteArrayInputStream(streamBytes);
131         ObjectInputStream ois  = new ObjectInputStream(bais);
132         return (T) ois.readObject();
133     }
134 
serializeDeserialize(T obj)135     static <T> T serializeDeserialize(T obj)
136         throws IOException, ClassNotFoundException
137     {
138         return deserialize(serialize(obj));
139     }
140 }
141