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 package test.java.io.Serializable.records; 24 25 /* 26 * @test 27 * @bug 8246774 28 * @summary Checks that the appropriate default value is given to the canonical ctr 29 * @run testng AbsentStreamValuesTest 30 * @run testng/othervm/java.security.policy=empty_security.policy AbsentStreamValuesTest 31 */ 32 33 import java.io.ByteArrayInputStream; 34 import java.io.ByteArrayOutputStream; 35 import java.io.DataOutputStream; 36 import java.io.IOException; 37 import java.io.ObjectInputStream; 38 import java.io.Serializable; 39 import org.testng.annotations.DataProvider; 40 import org.testng.annotations.Test; 41 import static java.io.ObjectStreamConstants.*; 42 import static java.lang.System.out; 43 import static org.testng.Assert.*; 44 45 /** 46 * Basic test to check that default primitive / reference values are presented 47 * to the record's canonical constructor, for fields not in the stream. 48 */ 49 public class AbsentStreamValuesTest { 50 51 record R01(boolean x) implements Serializable { } 52 record R02(byte x) implements Serializable { } 53 record R03(short x) implements Serializable { } 54 record R04(char x) implements Serializable { } 55 record R05(int x) implements Serializable { } 56 record R06(long x) implements Serializable { } 57 record R07(float x) implements Serializable { } 58 record R08(double x) implements Serializable { } 59 record R09(Object x) implements Serializable { } 60 record R10(String x) implements Serializable { } 61 record R11(int[] x) implements Serializable { } 62 record R12(Object[] x) implements Serializable { } 63 record R13(R12 x) implements Serializable { } 64 record R14(R13[] x) implements Serializable { } 65 66 @DataProvider(name = "recordTypeAndExpectedValue") recordTypeAndExpectedValue()67 public Object[][] recordTypeAndExpectedValue() { 68 return new Object[][] { 69 new Object[] { R01.class, false }, 70 new Object[] { R02.class, (byte)0 }, 71 new Object[] { R03.class, (short)0 }, 72 new Object[] { R04.class, '\u0000' }, 73 new Object[] { R05.class, 0 }, 74 new Object[] { R06.class, 0L }, 75 new Object[] { R07.class, 0.0f }, 76 new Object[] { R08.class, 0.0d }, 77 new Object[] { R09.class, null }, 78 new Object[] { R10.class, null }, 79 new Object[] { R11.class, null }, 80 new Object[] { R12.class, null }, 81 new Object[] { R13.class, null }, 82 new Object[] { R14.class, null }, 83 }; 84 } 85 86 @Test(dataProvider = "recordTypeAndExpectedValue") testWithDifferentTypes(Class<?> clazz, Object expectedXValue)87 public void testWithDifferentTypes(Class<?> clazz, Object expectedXValue) 88 throws Exception 89 { 90 out.println("\n---"); 91 assert clazz.isRecord(); 92 byte[] bytes = minimalByteStreamFor(clazz.getName()); 93 94 Object obj = deserialize(bytes); 95 out.println("deserialized: " + obj); 96 Object actualXValue = clazz.getDeclaredMethod("x").invoke(obj); 97 assertEquals(actualXValue, expectedXValue); 98 } 99 100 // --- all together 101 102 record R15(boolean a, byte b, short c, char d, int e, long f, float g, double h, Object i, String j, long[] k, Object[] l) 103 implements Serializable { } 104 105 @Test testWithAllTogether()106 public void testWithAllTogether() throws Exception { 107 out.println("\n---"); 108 byte[] bytes = minimalByteStreamFor(R15.class.getName()); 109 110 R15 obj = (R15)deserialize(bytes); 111 out.println("deserialized: " + obj); 112 assertEquals(obj.a, false); 113 assertEquals(obj.b, 0); 114 assertEquals(obj.c, 0); 115 assertEquals(obj.d, '\u0000'); 116 assertEquals(obj.e, 0); 117 assertEquals(obj.f, 0l); 118 assertEquals(obj.g, 0f); 119 assertEquals(obj.h, 0d); 120 assertEquals(obj.i, null); 121 assertEquals(obj.j, null); 122 assertEquals(obj.k, null); 123 assertEquals(obj.l, null); 124 } 125 126 // --- generic type 127 128 record R16<T, U>(T t, U u) implements Serializable { } 129 130 @Test testGenericType()131 public void testGenericType() throws Exception { 132 out.println("\n---"); 133 byte[] bytes = minimalByteStreamFor(R16.class.getName()); 134 135 R16 obj = (R16)deserialize(bytes); 136 out.println("deserialized: " + obj); 137 assertEquals(obj.t, null); 138 assertEquals(obj.u, null); 139 } 140 141 // --- infra 142 143 /** 144 * Returns the serial bytes for the given class name. The stream 145 * will have no stream field values. 146 */ minimalByteStreamFor(String className)147 static byte[] minimalByteStreamFor(String className) throws Exception { 148 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 149 DataOutputStream dos = new DataOutputStream(baos); 150 dos.writeShort(STREAM_MAGIC); 151 dos.writeShort(STREAM_VERSION); 152 dos.writeByte(TC_OBJECT); 153 dos.writeByte(TC_CLASSDESC); 154 dos.writeUTF(className); 155 dos.writeLong(0L); 156 dos.writeByte(SC_SERIALIZABLE); 157 dos.writeShort(0); // number of fields 158 dos.writeByte(TC_ENDBLOCKDATA); // no annotations 159 dos.writeByte(TC_NULL); // no superclasses 160 dos.close(); 161 return baos.toByteArray(); 162 } 163 164 @SuppressWarnings("unchecked") deserialize(byte[] streamBytes)165 static <T> T deserialize(byte[] streamBytes) 166 throws IOException, ClassNotFoundException 167 { 168 ByteArrayInputStream bais = new ByteArrayInputStream(streamBytes); 169 ObjectInputStream ois = new ObjectInputStream(bais); 170 return (T) ois.readObject(); 171 } 172 } 173