mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-16 10:53:31 +00:00
8254234: Add test library stream object builder
Reviewed-by: rriggs
This commit is contained in:
parent
4184959d85
commit
aad3cf4df7
@ -24,37 +24,25 @@
|
||||
/*
|
||||
* @test
|
||||
* @summary Checks that the appropriate value is given to the canonical ctr
|
||||
* @library /test/lib
|
||||
* @compile --enable-preview -source ${jdk.version} DifferentStreamFieldsTest.java
|
||||
* @run testng/othervm --enable-preview DifferentStreamFieldsTest
|
||||
* @run testng/othervm/java.security.policy=empty_security.policy --enable-preview DifferentStreamFieldsTest
|
||||
*/
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static java.io.ObjectStreamConstants.SC_SERIALIZABLE;
|
||||
import static java.io.ObjectStreamConstants.STREAM_MAGIC;
|
||||
import static java.io.ObjectStreamConstants.STREAM_VERSION;
|
||||
import static java.io.ObjectStreamConstants.TC_CLASSDESC;
|
||||
import static java.io.ObjectStreamConstants.TC_ENDBLOCKDATA;
|
||||
import static java.io.ObjectStreamConstants.TC_NULL;
|
||||
import static java.io.ObjectStreamConstants.TC_OBJECT;
|
||||
import static java.io.ObjectStreamConstants.TC_STRING;
|
||||
import static java.lang.System.out;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import jdk.test.lib.serial.SerialObjectBuilder;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
import static java.lang.System.out;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* Checks that the appropriate value is given to the canonical ctr.
|
||||
@ -114,7 +102,7 @@ public class DifferentStreamFieldsTest {
|
||||
throws Exception {
|
||||
out.println("\n---");
|
||||
assert clazz.isRecord();
|
||||
byte[] bytes = SerialByteStreamBuilder
|
||||
byte[] bytes = SerialObjectBuilder
|
||||
.newBuilder(clazz.getName())
|
||||
.build();
|
||||
|
||||
@ -123,7 +111,7 @@ public class DifferentStreamFieldsTest {
|
||||
Object actualXValue = clazz.getDeclaredMethod("x").invoke(obj);
|
||||
assertEquals(actualXValue, expectedXValue);
|
||||
|
||||
bytes = SerialByteStreamBuilder
|
||||
bytes = SerialObjectBuilder
|
||||
.newBuilder(clazz.getName())
|
||||
.addPrimitiveField("y", int.class, 5) // stream junk
|
||||
.build();
|
||||
@ -143,7 +131,7 @@ public class DifferentStreamFieldsTest {
|
||||
double h, Object i, String j, long[]k, Object[]l)
|
||||
implements Serializable {}
|
||||
|
||||
byte[] bytes = SerialByteStreamBuilder
|
||||
byte[] bytes = SerialObjectBuilder
|
||||
.newBuilder(R15.class.getName())
|
||||
.addPrimitiveField("x", int.class, 5) // stream junk
|
||||
.build();
|
||||
@ -173,7 +161,7 @@ public class DifferentStreamFieldsTest {
|
||||
var r = new R(5);
|
||||
byte[] OOSBytes = serialize(r);
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(R.class.getName())
|
||||
.addPrimitiveField("x", int.class, 5)
|
||||
.build();
|
||||
@ -191,7 +179,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser1 = deserialize(OOSBytes);
|
||||
assertEquals(deser1, r);
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(R.class.getName())
|
||||
.addPrimitiveField("x", int.class, 7)
|
||||
.addPrimitiveField("y", int.class, 8)
|
||||
@ -200,7 +188,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser2 = deserialize(builderBytes);
|
||||
assertEquals(deser2, deser1);
|
||||
|
||||
builderBytes = SerialByteStreamBuilder
|
||||
builderBytes = SerialObjectBuilder
|
||||
.newBuilder(R.class.getName())
|
||||
.addPrimitiveField("y", int.class, 8) // reverse order
|
||||
.addPrimitiveField("x", int.class, 7)
|
||||
@ -208,7 +196,7 @@ public class DifferentStreamFieldsTest {
|
||||
deser2 = deserialize(builderBytes);
|
||||
assertEquals(deser2, deser1);
|
||||
|
||||
builderBytes = SerialByteStreamBuilder
|
||||
builderBytes = SerialObjectBuilder
|
||||
.newBuilder(R.class.getName())
|
||||
.addPrimitiveField("w", int.class, 6) // additional fields
|
||||
.addPrimitiveField("x", int.class, 7)
|
||||
@ -223,7 +211,7 @@ public class DifferentStreamFieldsTest {
|
||||
deser1 = deserialize(OOSBytes);
|
||||
assertEquals(deser1, r);
|
||||
|
||||
builderBytes = SerialByteStreamBuilder
|
||||
builderBytes = SerialObjectBuilder
|
||||
.newBuilder(R.class.getName())
|
||||
.addPrimitiveField("y", int.class, 0)
|
||||
.addPrimitiveField("x", int.class, 0)
|
||||
@ -231,7 +219,7 @@ public class DifferentStreamFieldsTest {
|
||||
deser2 = deserialize(builderBytes);
|
||||
assertEquals(deser2, deser1);
|
||||
|
||||
builderBytes = SerialByteStreamBuilder
|
||||
builderBytes = SerialObjectBuilder
|
||||
.newBuilder(R.class.getName()) // no field values
|
||||
.build();
|
||||
deser2 = deserialize(builderBytes);
|
||||
@ -249,7 +237,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser1 = deserialize(serialize(r));
|
||||
assertEquals(deser1, r);
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(Str.class.getName())
|
||||
.addField("part1", String.class, "Hello")
|
||||
.addField("part2", String.class, "World!")
|
||||
@ -258,7 +246,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser2 = deserialize(builderBytes);
|
||||
assertEquals(deser2, deser1);
|
||||
|
||||
builderBytes = SerialByteStreamBuilder
|
||||
builderBytes = SerialObjectBuilder
|
||||
.newBuilder(Str.class.getName())
|
||||
.addField("cruft", String.class, "gg")
|
||||
.addField("part1", String.class, "Hello")
|
||||
@ -280,7 +268,7 @@ public class DifferentStreamFieldsTest {
|
||||
assertEquals(deser1.ints(), r.ints());
|
||||
assertEquals(deser1.longs(), r.longs());
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(IntArray.class.getName())
|
||||
.addField("ints", int[].class, new int[]{5, 4, 3, 2, 1})
|
||||
.addField("longs", long[].class, new long[]{9L})
|
||||
@ -296,7 +284,7 @@ public class DifferentStreamFieldsTest {
|
||||
StrArray deser1 = deserialize(serialize(r));
|
||||
assertEquals(deser1.stringArray(), r.stringArray());
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(StrArray.class.getName())
|
||||
.addField("stringArray", String[].class, new String[]{"foo", "bar"})
|
||||
.build();
|
||||
@ -317,7 +305,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser1 = deserialize(serialize(r));
|
||||
assertEquals(deser1, r);
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(NumberHolder.class.getName())
|
||||
.addField("n", Integer.class, 123)
|
||||
.build();
|
||||
@ -333,7 +321,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser1 = deserialize(serialize(r));
|
||||
assertEquals(deser1, r);
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(IntegerHolder.class.getName())
|
||||
.addField("i", Number.class, 123)
|
||||
.build();
|
||||
@ -353,7 +341,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser1 = deserialize(serialize(r));
|
||||
assertEquals(deser1, r);
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(StringHolder.class.getName())
|
||||
.addField("s", Integer.class, 123)
|
||||
.build();
|
||||
@ -377,7 +365,7 @@ public class DifferentStreamFieldsTest {
|
||||
var deser1 = deserialize(serialize(r));
|
||||
assertEquals(deser1, r);
|
||||
|
||||
byte[] builderBytes = SerialByteStreamBuilder
|
||||
byte[] builderBytes = SerialObjectBuilder
|
||||
.newBuilder(IntHolder.class.getName())
|
||||
.addPrimitiveField("i", long.class, 123L)
|
||||
.build();
|
||||
@ -406,158 +394,4 @@ public class DifferentStreamFieldsTest {
|
||||
ObjectInputStream ois = new ObjectInputStream(bais);
|
||||
return (T) ois.readObject();
|
||||
}
|
||||
|
||||
static class SerialByteStreamBuilder {
|
||||
|
||||
private final ObjectOutputStream objectOutputStream;
|
||||
private final ByteArrayOutputStream byteArrayOutputStream;
|
||||
|
||||
record NameAndType<T>(String name, Class<T>type) {}
|
||||
|
||||
private String className;
|
||||
private final LinkedHashMap<NameAndType<?>, Object> primFields = new LinkedHashMap<>();
|
||||
private final LinkedHashMap<NameAndType<?>, Object> objectFields = new LinkedHashMap<>();
|
||||
|
||||
private SerialByteStreamBuilder() {
|
||||
try {
|
||||
byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SerialByteStreamBuilder newBuilder(String className) {
|
||||
return (new SerialByteStreamBuilder()).className(className);
|
||||
}
|
||||
|
||||
private SerialByteStreamBuilder className(String className) {
|
||||
this.className = className;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> SerialByteStreamBuilder addPrimitiveField(String name, Class<T> type, T value) {
|
||||
if (!type.isPrimitive())
|
||||
throw new IllegalArgumentException("Unexpected non-primitive field: " + type);
|
||||
primFields.put(new NameAndType<>(name, type), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> SerialByteStreamBuilder addField(String name, Class<T> type, T value) {
|
||||
if (type.isPrimitive())
|
||||
throw new IllegalArgumentException("Unexpected primitive field: " + type);
|
||||
objectFields.put(new NameAndType<>(name, type), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static int getPrimitiveSignature(Class<?> cl) {
|
||||
if (cl == Integer.TYPE) return 'I';
|
||||
else if (cl == Byte.TYPE) return 'B';
|
||||
else if (cl == Long.TYPE) return 'J';
|
||||
else if (cl == Float.TYPE) return 'F';
|
||||
else if (cl == Double.TYPE) return 'D';
|
||||
else if (cl == Short.TYPE) return 'S';
|
||||
else if (cl == Character.TYPE) return 'C';
|
||||
else if (cl == Boolean.TYPE) return 'Z';
|
||||
else throw new InternalError();
|
||||
}
|
||||
|
||||
private static void writeUTF(DataOutputStream out, String str) throws IOException {
|
||||
int utflen = str.length(); // assume ASCII
|
||||
assert utflen <= 0xFFFF;
|
||||
out.writeShort(utflen);
|
||||
out.writeBytes(str);
|
||||
}
|
||||
|
||||
private void writePrimFieldsDesc(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : primFields.entrySet()) {
|
||||
assert entry.getKey().type() != void.class;
|
||||
out.writeByte(getPrimitiveSignature(entry.getKey().type())); // prim_typecode
|
||||
out.writeUTF(entry.getKey().name()); // fieldName
|
||||
}
|
||||
}
|
||||
|
||||
private void writePrimFieldsValues(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : primFields.entrySet()) {
|
||||
Class<?> cl = entry.getKey().type();
|
||||
Object value = entry.getValue();
|
||||
if (cl == Integer.TYPE) out.writeInt((int) value);
|
||||
else if (cl == Byte.TYPE) out.writeByte((byte) value);
|
||||
else if (cl == Long.TYPE) out.writeLong((long) value);
|
||||
else if (cl == Float.TYPE) out.writeFloat((float) value);
|
||||
else if (cl == Double.TYPE) out.writeDouble((double) value);
|
||||
else if (cl == Short.TYPE) out.writeShort((short) value);
|
||||
else if (cl == Character.TYPE) out.writeChar((char) value);
|
||||
else if (cl == Boolean.TYPE) out.writeBoolean((boolean) value);
|
||||
else throw new InternalError();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObjectFieldDesc(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : objectFields.entrySet()) {
|
||||
Class<?> cl = entry.getKey().type();
|
||||
assert !cl.isPrimitive();
|
||||
// obj_typecode
|
||||
if (cl.isArray()) {
|
||||
out.writeByte('[');
|
||||
} else {
|
||||
out.writeByte('L');
|
||||
}
|
||||
writeUTF(out, entry.getKey().name());
|
||||
out.writeByte(TC_STRING);
|
||||
writeUTF(out,
|
||||
(cl.isArray() ? cl.getName() : "L" + cl.getName() + ";")
|
||||
.replace('.', '/'));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(DataOutputStream out, Object value) throws IOException {
|
||||
objectOutputStream.reset();
|
||||
byteArrayOutputStream.reset();
|
||||
objectOutputStream.writeUnshared(value);
|
||||
out.write(byteArrayOutputStream.toByteArray());
|
||||
}
|
||||
|
||||
private void writeObjectFieldValues(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : objectFields.entrySet()) {
|
||||
Class<?> cl = entry.getKey().type();
|
||||
assert !cl.isPrimitive();
|
||||
if (cl == String.class) {
|
||||
out.writeByte(TC_STRING);
|
||||
writeUTF(out, (String) entry.getValue());
|
||||
} else {
|
||||
writeObject(out, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int numFields() {
|
||||
return primFields.size() + objectFields.size();
|
||||
}
|
||||
|
||||
public byte[] build() {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(baos);
|
||||
dos.writeShort(STREAM_MAGIC);
|
||||
dos.writeShort(STREAM_VERSION);
|
||||
dos.writeByte(TC_OBJECT);
|
||||
dos.writeByte(TC_CLASSDESC);
|
||||
dos.writeUTF(className);
|
||||
dos.writeLong(0L);
|
||||
dos.writeByte(SC_SERIALIZABLE);
|
||||
dos.writeShort(numFields()); // number of fields
|
||||
writePrimFieldsDesc(dos);
|
||||
writeObjectFieldDesc(dos);
|
||||
dos.writeByte(TC_ENDBLOCKDATA); // no annotations
|
||||
dos.writeByte(TC_NULL); // no superclasses
|
||||
writePrimFieldsValues(dos);
|
||||
writeObjectFieldValues(dos);
|
||||
dos.close();
|
||||
return baos.toByteArray();
|
||||
} catch (IOException unexpected) {
|
||||
throw new AssertionError(unexpected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
206
test/lib/jdk/test/lib/serial/SerialObjectBuilder.java
Normal file
206
test/lib/jdk/test/lib/serial/SerialObjectBuilder.java
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.test.lib.serial;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import static java.io.ObjectStreamConstants.*;
|
||||
|
||||
/**
|
||||
* A basic builder of a serial object.
|
||||
*/
|
||||
public class SerialObjectBuilder {
|
||||
|
||||
private final ObjectOutputStream objectOutputStream;
|
||||
private final ByteArrayOutputStream byteArrayOutputStream;
|
||||
|
||||
private record NameAndType<T>(String name, Class<T>type) { }
|
||||
|
||||
private String className;
|
||||
private long suid;
|
||||
private SerialObjectBuilder superClass;
|
||||
private final LinkedHashMap<NameAndType<?>, Object> primFields = new LinkedHashMap<>();
|
||||
private final LinkedHashMap<NameAndType<?>, Object> objectFields = new LinkedHashMap<>();
|
||||
|
||||
private SerialObjectBuilder() {
|
||||
try {
|
||||
byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SerialObjectBuilder newBuilder(String className) {
|
||||
return (new SerialObjectBuilder()).className(className);
|
||||
}
|
||||
|
||||
private SerialObjectBuilder className(String className) {
|
||||
this.className = className;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerialObjectBuilder suid(long suid) {
|
||||
this.suid = suid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SerialObjectBuilder superClass(SerialObjectBuilder superClass) {
|
||||
this.superClass = superClass;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> SerialObjectBuilder addPrimitiveField(String name, Class<T> type, T value) {
|
||||
if (!type.isPrimitive())
|
||||
throw new IllegalArgumentException("Unexpected non-primitive field: " + type);
|
||||
primFields.put(new NameAndType<>(name, type), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> SerialObjectBuilder addField(String name, Class<T> type, T value) {
|
||||
if (type.isPrimitive())
|
||||
throw new IllegalArgumentException("Unexpected primitive field: " + type);
|
||||
objectFields.put(new NameAndType<>(name, type), value);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static void writeUTF(DataOutputStream out, String str) throws IOException {
|
||||
assert str.codePoints().noneMatch(cp -> cp > 127); // only ASCII for now
|
||||
int utflen = str.length();
|
||||
assert utflen <= 0xFFFF; // only small strings for now
|
||||
out.writeShort(utflen);
|
||||
out.writeBytes(str);
|
||||
}
|
||||
|
||||
private void writePrimFieldsDesc(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : primFields.entrySet()) {
|
||||
Class<?> primClass = entry.getKey().type();
|
||||
assert primClass.isPrimitive();
|
||||
assert primClass != void.class;
|
||||
out.writeByte(primClass.descriptorString().getBytes()[0]); // prim_typecode
|
||||
out.writeUTF(entry.getKey().name()); // fieldName
|
||||
}
|
||||
}
|
||||
|
||||
private void writePrimFieldsValues(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : primFields.entrySet()) {
|
||||
Class<?> cl = entry.getKey().type();
|
||||
Object value = entry.getValue();
|
||||
if (cl == Integer.TYPE) out.writeInt((int) value);
|
||||
else if (cl == Byte.TYPE) out.writeByte((byte) value);
|
||||
else if (cl == Long.TYPE) out.writeLong((long) value);
|
||||
else if (cl == Float.TYPE) out.writeFloat((float) value);
|
||||
else if (cl == Double.TYPE) out.writeDouble((double) value);
|
||||
else if (cl == Short.TYPE) out.writeShort((short) value);
|
||||
else if (cl == Character.TYPE) out.writeChar((char) value);
|
||||
else if (cl == Boolean.TYPE) out.writeBoolean((boolean) value);
|
||||
else throw new InternalError();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObjectFieldDesc(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : objectFields.entrySet()) {
|
||||
Class<?> cl = entry.getKey().type();
|
||||
assert !cl.isPrimitive();
|
||||
// obj_typecode
|
||||
if (cl.isArray()) {
|
||||
out.writeByte('[');
|
||||
} else {
|
||||
out.writeByte('L');
|
||||
}
|
||||
writeUTF(out, entry.getKey().name());
|
||||
out.writeByte(TC_STRING);
|
||||
writeUTF(out, cl.descriptorString());
|
||||
}
|
||||
}
|
||||
|
||||
private void writeObject(DataOutputStream out, Object value) throws IOException {
|
||||
objectOutputStream.reset();
|
||||
byteArrayOutputStream.reset();
|
||||
objectOutputStream.writeUnshared(value);
|
||||
out.write(byteArrayOutputStream.toByteArray());
|
||||
}
|
||||
|
||||
private void writeObjectFieldValues(DataOutputStream out) throws IOException {
|
||||
for (Map.Entry<NameAndType<?>, Object> entry : objectFields.entrySet()) {
|
||||
Class<?> cl = entry.getKey().type();
|
||||
assert !cl.isPrimitive();
|
||||
if (cl == String.class) {
|
||||
out.writeByte(TC_STRING);
|
||||
writeUTF(out, (String) entry.getValue());
|
||||
} else {
|
||||
writeObject(out, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int numFields() {
|
||||
return primFields.size() + objectFields.size();
|
||||
}
|
||||
|
||||
private static void writeClassDesc(DataOutputStream dos,
|
||||
SerialObjectBuilder sb)
|
||||
throws IOException
|
||||
{
|
||||
dos.writeByte(TC_CLASSDESC);
|
||||
dos.writeUTF(sb.className);
|
||||
dos.writeLong(sb.suid);
|
||||
dos.writeByte(SC_SERIALIZABLE);
|
||||
dos.writeShort(sb.numFields()); // number of fields
|
||||
sb.writePrimFieldsDesc(dos);
|
||||
sb.writeObjectFieldDesc(dos);
|
||||
dos.writeByte(TC_ENDBLOCKDATA); // no annotations
|
||||
if (sb.superClass == null) {
|
||||
dos.writeByte(TC_NULL); // no superclasses
|
||||
} else {
|
||||
writeClassDesc(dos, sb.superClass);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] build() {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DataOutputStream dos = new DataOutputStream(baos);
|
||||
dos.writeShort(STREAM_MAGIC);
|
||||
dos.writeShort(STREAM_VERSION);
|
||||
dos.writeByte(TC_OBJECT);
|
||||
writeClassDesc(dos, this);
|
||||
if (superClass != null) {
|
||||
superClass.writePrimFieldsValues(dos);
|
||||
superClass.writeObjectFieldValues(dos);
|
||||
}
|
||||
writePrimFieldsValues(dos);
|
||||
writeObjectFieldValues(dos);
|
||||
dos.close();
|
||||
return baos.toByteArray();
|
||||
} catch (IOException unexpected) {
|
||||
throw new AssertionError(unexpected);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user