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 readResolve
28  * @run testng ReadResolveTest
29  * @run testng/othervm/java.security.policy=empty_security.policy ReadResolveTest
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.Serial;
39 import java.io.Serializable;
40 import org.testng.annotations.DataProvider;
41 import org.testng.annotations.Test;
42 import static java.lang.String.format;
43 import static java.lang.System.out;
44 import static org.testng.Assert.assertEquals;
45 
46 /**
47  * Tests records being used as a serial proxy.
48  */
49 public class ReadResolveTest {
50 
51     static class C1 implements Serializable {
52         private final int x;
53         private final int y;
C1(int x, int y)54         C1(int x, int y) { this.x = x; this.y = y; }
55         private record SerProxy1(int x, int y) implements Serializable {
56             @Serial
readResolve()57             private Object readResolve() { return new C1(x, y); }
58         }
59         @Serial
writeReplace()60         private Object writeReplace() {
61             return new SerProxy1(x, y);
62         }
63         @Override
equals(Object obj)64         public boolean equals(Object obj) {
65             return obj != null && obj instanceof C1 && ((C1)obj).x == this.x && ((C1)obj).y == y;
66         }
67         @Override
toString()68         public String toString() { return format("C1[x=%x, y=%d]", x, y); }
69     }
70 
71     static class C2 implements Serializable {
72         private record SerProxy2() implements Serializable {
73             @Serial
readResolve()74             private Object readResolve() { return new C2(); }
75         }
76         @Serial
writeReplace()77         private Object writeReplace() {
78             return new SerProxy2();
79         }
80         @Override
equals(Object obj)81         public boolean equals(Object obj) {
82             return obj != null && obj instanceof C2;
83         }
84         @Override
toString()85         public String toString() { return "C2[]"; }
86     }
87 
88     record R1 (int x, int y, String s) implements Serializable {
89         private record SerProxy3(int a, int b, String c) implements Serializable {
90             @Serial
readResolve()91             private Object readResolve() { return new R1(a, b, c); }
92         }
93         @Serial
writeReplace()94         private Object writeReplace() {
95             return new SerProxy3(x, y, s);
96         }
97     }
98 
99     @DataProvider(name = "objectsToSerialize")
objectsToSerialize()100     public Object[][] objectsToSerialize() {
101         return new Object[][] {
102                 new Object[] { new C1(3,4)        },
103                 new Object[] { new C2()           },
104                 new Object[] { new R1(5, 6, "c")  }
105         };
106     }
107 
108     @Test(dataProvider = "objectsToSerialize")
testSerialize(Object objectToSerialize)109     public void testSerialize(Object objectToSerialize) throws Exception {
110         out.println("\n---");
111         out.println("serializing : " + objectToSerialize);
112         Object deserializedObj = serializeDeserialize(objectToSerialize);
113         out.println("deserialized: " + deserializedObj);
114         assertEquals(deserializedObj, objectToSerialize);
115     }
116 
117     // -- null replacement
118 
119     record R10 () implements Serializable {
120         @Serial
readResolve()121         private Object readResolve() {
122             return null;
123         }
124     }
125 
126     @Test
testNull()127     public void testNull() throws Exception {
128         out.println("\n---");
129         Object objectToSerialize = new R10();
130         out.println("serializing : " + objectToSerialize);
131         Object deserializedObj = serializeDeserialize(objectToSerialize);
132         out.println("deserialized: " + deserializedObj);
133         assertEquals(deserializedObj, null);
134     }
135 
136     // --- infra
137 
serialize(T obj)138     static <T> byte[] serialize(T obj) throws IOException {
139         ByteArrayOutputStream baos = new ByteArrayOutputStream();
140         ObjectOutputStream oos = new ObjectOutputStream(baos);
141         oos.writeObject(obj);
142         oos.close();
143         return baos.toByteArray();
144     }
145 
146     @SuppressWarnings("unchecked")
deserialize(byte[] streamBytes)147     static <T> T deserialize(byte[] streamBytes)
148         throws IOException, ClassNotFoundException
149     {
150         ByteArrayInputStream bais = new ByteArrayInputStream(streamBytes);
151         ObjectInputStream ois  = new ObjectInputStream(bais);
152         return (T) ois.readObject();
153     }
154 
serializeDeserialize(T obj)155     static <T> T serializeDeserialize(T obj)
156         throws IOException, ClassNotFoundException
157     {
158         return deserialize(serialize(obj));
159     }
160 }
161 
162