1 /*
2  * Copyright (c) 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 8238763 8246774
27  * @summary ObjectInputStream readUnshared method handling of Records
28  * @run testng UnsharedTest
29  */
30 package test.java.io.Serializable.records;
31 
32 import java.io.ByteArrayInputStream;
33 import java.io.ByteArrayOutputStream;
34 import java.io.IOException;
35 import java.io.InvalidObjectException;
36 import java.io.ObjectInputStream;
37 import java.io.ObjectOutputStream;
38 import java.io.Serializable;
39 import org.testng.annotations.Test;
40 import static org.testng.Assert.assertEquals;
41 import static org.testng.Assert.assertTrue;
42 import static org.testng.Assert.expectThrows;
43 
44 /**
45  * Tests OOS::writeUnshared and OIS::readUnshared to verify that records
46  * are correctly unshared in the stream as appropriate.
47  */
48 public class UnsharedTest {
49 
50     record Foo(int x) implements Serializable { }
51 
52     static final Class<InvalidObjectException> IOE = InvalidObjectException.class;
53 
54     @Test
testReadUnshared()55     public void testReadUnshared() throws Exception {
56         var foo = new Foo(6);
57         {  // shared - sanity to ensure the second foo is a ref
58             var byteStream = serialize(foo, foo);
59             var foo1 = (Foo) deserializeOne(byteStream);
60             assertEquals(foo1.x, foo.x);
61             var foo2 = (Foo) deserializeOne(byteStream);
62             assertEquals(foo2.x, foo.x);
63             assertTrue(foo2 == foo1);
64         }
65         {  // unshared
66             var byteStream = serialize(foo, foo);
67             var foo1 = (Foo) deserializeOneUnshared(byteStream);
68             assertEquals(foo1.x, foo.x);
69             var expected = expectThrows(IOE, () -> deserializeOne(byteStream));
70             assertTrue(expected.getMessage().contains("cannot read back reference to unshared object"));
71         }
72     }
73 
74     @Test
testWriteUnshared()75     public void testWriteUnshared() throws Exception {
76         var foo = new Foo(7);
77         {  // shared - sanity to ensure the second foo is NOT a ref
78             var byteStream = serializeUnshared(foo, foo);
79             var foo1 = (Foo) deserializeOne(byteStream);
80             assertEquals(foo1.x, foo.x);
81             var foo2 = (Foo) deserializeOne(byteStream);
82             assertEquals(foo2.x, foo.x);
83             assertTrue(foo2 != foo1);
84         }
85         {  // unshared
86             var byteStream = serializeUnshared(foo, foo);
87             var foo1 = (Foo) deserializeOneUnshared(byteStream);
88             assertEquals(foo1.x, foo.x);
89             var foo2 = (Foo) deserializeOneUnshared(byteStream);
90             assertEquals(foo2.x, foo.x);
91             assertTrue(foo2 != foo1);
92         }
93     }
94 
95     // ---
96 
serialize(Object... objs)97     static ObjectInputStream serialize(Object... objs) throws IOException {
98         ByteArrayOutputStream baos = new ByteArrayOutputStream();
99         ObjectOutputStream oos = new ObjectOutputStream(baos);
100         for (Object obj : objs)
101             oos.writeObject(obj);
102         oos.close();
103         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
104         return new ObjectInputStream(bais);
105     }
106 
serializeUnshared(Object... objs)107     static ObjectInputStream serializeUnshared(Object... objs) throws IOException {
108         ByteArrayOutputStream baos = new ByteArrayOutputStream();
109         ObjectOutputStream oos = new ObjectOutputStream(baos);
110         for (Object obj : objs)
111             oos.writeUnshared(obj);
112         oos.close();
113         ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
114         return new ObjectInputStream(bais);
115     }
116 
117     @SuppressWarnings("unchecked")
deserializeOne(ObjectInputStream ois)118     static Object deserializeOne(ObjectInputStream ois)
119         throws IOException, ClassNotFoundException
120     {
121         return ois.readObject();
122     }
123 
124     @SuppressWarnings("unchecked")
deserializeOneUnshared(ObjectInputStream ois)125     static Object deserializeOneUnshared(ObjectInputStream ois)
126         throws IOException, ClassNotFoundException
127     {
128         return ois.readUnshared();
129     }
130 }
131