From 53e468aa68245a5a979dbef90a0bccf2480c1f94 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 17 Oct 2022 23:33:30 +0200 Subject: [PATCH] INCOMPLETE: Add non-fluent builder API TODO: - Proper package names - Proper tests - Code generation support - Renaming of existing builders (?) Resolves #2 --- .../implementation/ClassTypeNameHelper.java | 23 +- .../simplebuilder2/EnumConstant.java | 10 + .../simplebuilder2/ExternalizableObject.java | 15 ++ .../simplebuilder2/FactoryMethods.java | 229 ++++++++++++++++++ .../HandleAssignableObject.java | 23 ++ .../simplebuilder2/NullObject.java | 14 ++ .../simplebuilder2/ObjectBase.java | 13 + .../simplebuilder2/ObjectDataWriter.java | 94 +++++++ .../simplebuilder2/ObjectHandle.java | 14 ++ .../ProxyInvocationHandlerObject.java | 7 + .../simplebuilder2/ProxyObject.java | 20 ++ .../simplebuilder2/SerializableObject.java | 30 +++ .../simplebuilder2/SerializedField.java | 9 + .../simplebuilder2/StringObject.java | 10 + .../simplebuilder2/array/BooleanArray.java | 12 + .../simplebuilder2/array/ByteArray.java | 12 + .../simplebuilder2/array/CharArray.java | 12 + .../simplebuilder2/array/DoubleArray.java | 12 + .../simplebuilder2/array/FloatArray.java | 12 + .../simplebuilder2/array/IntArray.java | 12 + .../simplebuilder2/array/LongArray.java | 12 + .../simplebuilder2/array/ObjectArray.java | 18 ++ .../simplebuilder2/array/ShortArray.java | 12 + .../simplebuilder2/classdata/ClassData.java | 29 +++ .../simplebuilder2/classdata/ObjectField.java | 18 ++ .../classdata/PrimitiveField.java | 62 +++++ .../classobject/ClassObject.java | 6 + .../simplebuilder2/classobject/EnumClass.java | 11 + .../classobject/ExternalizableClass.java | 10 + .../classobject/NonSerializableClass.java | 11 + .../classobject/ProxyClass.java | 12 + .../classobject/SerializableClass.java | 11 + .../serialization/serialbuilder/V2Test.java | 63 +++++ 33 files changed, 849 insertions(+), 9 deletions(-) create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/EnumConstant.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ExternalizableObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/FactoryMethods.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/HandleAssignableObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/NullObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectBase.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectDataWriter.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectHandle.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyInvocationHandlerObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializableObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializedField.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/StringObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/BooleanArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ByteArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/CharArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/DoubleArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/FloatArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/IntArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/LongArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ObjectArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ShortArray.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ClassData.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ObjectField.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/PrimitiveField.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ClassObject.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/EnumClass.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ExternalizableClass.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/NonSerializableClass.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ProxyClass.java create mode 100644 serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/SerializableClass.java create mode 100644 serial-builder/src/test/java/marcono1234/serialization/serialbuilder/V2Test.java diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/builder/implementation/ClassTypeNameHelper.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/builder/implementation/ClassTypeNameHelper.java index 0117a39..7297e99 100644 --- a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/builder/implementation/ClassTypeNameHelper.java +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/builder/implementation/ClassTypeNameHelper.java @@ -1,5 +1,8 @@ package marcono1234.serialization.serialbuilder.builder.implementation; +import java.util.Arrays; +import java.util.List; + public class ClassTypeNameHelper { private ClassTypeNameHelper() { } @@ -19,15 +22,17 @@ public static String getObjectTypeName(Class fieldType) { } public static String[] getInterfaceNames(Class... interfaces) { - String[] interfacesNames = new String[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) { - Class interface_ = interfaces[i]; - if (!interface_.isInterface()) { - throw new IllegalArgumentException("Not an interface: " + interface_.getTypeName()); - } + return getInterfaceNames(Arrays.asList(interfaces)); + } - interfacesNames[i] = interfaces[i].getTypeName(); - } - return interfacesNames; + public static String[] getInterfaceNames(List> interfaces) { + return interfaces.stream() + .map(c -> { + if (!c.isInterface()) { + throw new IllegalArgumentException("Not an interface: " + c.getTypeName()); + } + return c.getTypeName(); + }) + .toArray(String[]::new); } } diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/EnumConstant.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/EnumConstant.java new file mode 100644 index 0000000..f52002b --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/EnumConstant.java @@ -0,0 +1,10 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +public record EnumConstant(String enumClass, String constantName) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.enumConstant(enumClass, constantName); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ExternalizableObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ExternalizableObject.java new file mode 100644 index 0000000..918750a --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ExternalizableObject.java @@ -0,0 +1,15 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.builder.api.ThrowingConsumer; +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +public record ExternalizableObject( + String typeName, + long serialVersionUID, + ThrowingConsumer writer +) implements ProxyInvocationHandlerObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.externalizableObject(typeName, serialVersionUID, delegateWriter -> writer.accept(new ObjectDataWriter(delegateWriter))); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/FactoryMethods.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/FactoryMethods.java new file mode 100644 index 0000000..7c07e31 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/FactoryMethods.java @@ -0,0 +1,229 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.builder.api.ThrowingConsumer; +import marcono1234.serialization.serialbuilder.builder.implementation.ClassTypeNameHelper; +import marcono1234.serialization.serialbuilder.builder.implementation.SerialVersionUidHelper; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.BooleanArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.ByteArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.CharArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.DoubleArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.FloatArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.IntArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.LongArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.ObjectArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.ShortArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.classdata.ClassData; +import marcono1234.serialization.serialbuilder.simplebuilder2.classdata.ObjectField; +import marcono1234.serialization.serialbuilder.simplebuilder2.classdata.PrimitiveField; +import marcono1234.serialization.serialbuilder.simplebuilder2.classobject.ClassObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.classobject.EnumClass; +import marcono1234.serialization.serialbuilder.simplebuilder2.classobject.ExternalizableClass; +import marcono1234.serialization.serialbuilder.simplebuilder2.classobject.NonSerializableClass; +import marcono1234.serialization.serialbuilder.simplebuilder2.classobject.ProxyClass; +import marcono1234.serialization.serialbuilder.simplebuilder2.classobject.SerializableClass; + +import java.io.Externalizable; +import java.io.Serializable; +import java.lang.reflect.Proxy; +import java.util.List; + +public class FactoryMethods { + private FactoryMethods() {} + + public static BooleanArray array(boolean[] array) { + return new BooleanArray(array); + } + + public static ByteArray array(byte[] array) { + return new ByteArray(array); + } + + public static CharArray array(char[] array) { + return new CharArray(array); + } + + public static ShortArray array(short[] array) { + return new ShortArray(array); + } + + public static IntArray array(int[] array) { + return new IntArray(array); + } + + public static LongArray array(long[] array) { + return new LongArray(array); + } + + public static FloatArray array(float[] array) { + return new FloatArray(array); + } + + public static DoubleArray array(double[] array) { + return new DoubleArray(array); + } + + public static ObjectArray objectArray(String arrayType, List elements) { + return new ObjectArray(arrayType, elements); + } + + public static ObjectArray objectArray(Class arrayType, List elements) { + return objectArray(arrayType.getTypeName(), elements); + } + + public static NullObject nullObject() { + return NullObject.INSTANCE; + } + + public static StringObject string(String s) { + return new StringObject(s); + } + + public static EnumConstant enumConstant(String enumClass, String constantName) { + return new EnumConstant(enumClass, constantName); + } + + public static EnumConstant enumConstant(Class> enumClass, String constantName) { + return enumConstant(enumClass.getTypeName(), constantName); + } + + public static > EnumConstant enumConstant(E enumConstant) { + return enumConstant(enumConstant.getDeclaringClass(), enumConstant.name()); + } + + public static NonSerializableClass nonSerializableClass(String className) { + return new NonSerializableClass(className); + } + + public static ExternalizableClass externalizableClass(String className, long serialVersionUID) { + return new ExternalizableClass(className, serialVersionUID); + } + + public static SerializableClass serializableClass(String className, long serialVersionUID) { + return new SerializableClass(className, serialVersionUID); + } + + public static ClassObject arrayClass(String className) { + // For array and record serialVersionUID is ignored, see https://docs.oracle.com/en/java/javase/17/docs/specs/serialization/class.html#stream-unique-identifiers + return serializableClass(className, 0); + } + + public static ClassObject recordClass(String className) { + // For array and record serialVersionUID is ignored, see https://docs.oracle.com/en/java/javase/17/docs/specs/serialization/class.html#stream-unique-identifiers + return serializableClass(className, 0); + } + + public static EnumClass enumClass(String className) { + return new EnumClass(className); + } + + public static ProxyClass proxyClass(String... interfaceNames) { + return new ProxyClass(List.of(interfaceNames)); + } + + public static ProxyClass proxyClass(Class... interfaces) { + return proxyClass(ClassTypeNameHelper.getInterfaceNames(interfaces)); + } + + public static ClassObject classObject(Class c) { + String className = c.getTypeName(); + + if (Proxy.isProxyClass(c)) { + return proxyClass(c.getInterfaces()); + } + // ObjectStreamClass also considers Enum.class to be an enum (unlike `Class.isEnum()`) + else if (c.isEnum() || c == Enum.class) { + return enumClass(className); + } else if (c.isArray()) { + return arrayClass(className); + } else if (c.isRecord()) { + return recordClass(className); + } else if (Externalizable.class.isAssignableFrom(c)) { + return externalizableClass(className, SerialVersionUidHelper.getSerialVersionUID(c)); + } else if (Serializable.class.isAssignableFrom(c)){ + return serializableClass(className, SerialVersionUidHelper.getSerialVersionUID(c)); + } else { + return nonSerializableClass(className); + } + } + + public static SerializableObject serializableObject(ClassData... classData) { + return new SerializableObject(List.of(classData)); + } + + public static ExternalizableObject externalizableObject(String typeName, long serialVersionUID, ThrowingConsumer writer) { + return new ExternalizableObject(typeName, serialVersionUID, writer); + } + + public static ExternalizableObject externalizableObject(Class c, ThrowingConsumer writer) { + return externalizableObject(c.getTypeName(), SerialVersionUidHelper.getSerialVersionUID(c), writer); + } + + public static ProxyObject proxyObject(List interfaceNames, ProxyInvocationHandlerObject invocationHandler) { + return new ProxyObject(interfaceNames, invocationHandler); + } + + // TODO: Signature clashes due to erasure + /* + public static ProxyObject proxyObject(List> interfaces, ProxyInvocationHandlerObject invocationHandler) { + return proxyObject(ClassTypeNameHelper.getInterfaceNames(interfaces), invocationHandler); + } + */ + + /* Serializable object class data factory methods */ + + public static ClassData classData(String className, long serialVersionUID, List fields, ThrowingConsumer dataWriter) { + return new ClassData(className, serialVersionUID, fields, dataWriter); + } + + public static ClassData classData(String className, long serialVersion, List fields) { + return classData(className, serialVersion, fields, null); + } + + public static ClassData classData(Class c, List fields, ThrowingConsumer dataWriter) { + return classData(c.getTypeName(), SerialVersionUidHelper.getSerialVersionUID(c), fields, dataWriter); + } + + public static ClassData classData(Class c, List fields) { + return classData(c, fields, null); + } + + public static PrimitiveField.BooleanField booleanField(String fieldName, boolean value) { + return new PrimitiveField.BooleanField(fieldName, value); + } + + public static PrimitiveField.ByteField byteField(String fieldName, byte value) { + return new PrimitiveField.ByteField(fieldName, value); + } + + public static PrimitiveField.CharField charField(String fieldName, char value) { + return new PrimitiveField.CharField(fieldName, value); + } + + public static PrimitiveField.ShortField shortField(String fieldName, short value) { + return new PrimitiveField.ShortField(fieldName, value); + } + + public static PrimitiveField.IntField intField(String fieldName, int value) { + return new PrimitiveField.IntField(fieldName, value); + } + + public static PrimitiveField.LongField longField(String fieldName, long value) { + return new PrimitiveField.LongField(fieldName, value); + } + + public static PrimitiveField.FloatField floatField(String fieldName, float value) { + return new PrimitiveField.FloatField(fieldName, value); + } + + public static PrimitiveField.DoubleField doubleField(String fieldName, double value) { + return new PrimitiveField.DoubleField(fieldName, value); + } + + public static ObjectField objectField(String fieldName, String fieldType, ObjectBase object) { + return new ObjectField(fieldName, fieldType, object); + } + + public static ObjectField objectField(String fieldName, Class fieldType, ObjectBase object) { + return objectField(fieldName, ClassTypeNameHelper.getObjectTypeName(fieldType), object); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/HandleAssignableObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/HandleAssignableObject.java new file mode 100644 index 0000000..8f956ca --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/HandleAssignableObject.java @@ -0,0 +1,23 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder2.array.BooleanArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.ByteArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.CharArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.DoubleArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.FloatArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.IntArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.LongArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.ObjectArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.array.ShortArray; +import marcono1234.serialization.serialbuilder.simplebuilder2.classobject.ClassObject; + +/* + * TODO: + * How to implement this? Should every implementing class store a Handle which it assigns once? But cannot reuse + * objects for separate builders then; in the future could maybe implement fluent API on top of this API. Then + * Handle of fluent API could internally store the HandleAssignableObject the fluent API created. When ObjectHandle + * is then written, the builder could check for reference equality to look up the previously written + * HandleAssignableObject. + */ +public sealed interface HandleAssignableObject extends ObjectBase permits EnumConstant, ProxyInvocationHandlerObject, StringObject, BooleanArray, ByteArray, CharArray, DoubleArray, FloatArray, IntArray, LongArray, ObjectArray, ShortArray, ClassObject { +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/NullObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/NullObject.java new file mode 100644 index 0000000..39df988 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/NullObject.java @@ -0,0 +1,14 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +public final class NullObject implements ObjectBase { + private NullObject() {} + + public static final NullObject INSTANCE = new NullObject(); + + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.nullObject(); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectBase.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectBase.java new file mode 100644 index 0000000..e0b86be --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectBase.java @@ -0,0 +1,13 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.SimpleSerialBuilder; +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +// TODO Better class name? +public sealed interface ObjectBase permits HandleAssignableObject, NullObject, ObjectHandle { + C buildSerialData(ObjectStart objectStart); + + default byte[] createSerialData() { + return SimpleSerialBuilder.writeSerializationDataWith(this::buildSerialData); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectDataWriter.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectDataWriter.java new file mode 100644 index 0000000..5867917 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectDataWriter.java @@ -0,0 +1,94 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.ObjectBuildingDataOutput; + +import java.io.DataOutput; +import java.io.IOException; +import java.util.Objects; + +public class ObjectDataWriter implements DataOutput { + private final ObjectBuildingDataOutput delegate; + + public ObjectDataWriter(ObjectBuildingDataOutput delegate) { + this.delegate = Objects.requireNonNull(delegate); + } + + public void object(ObjectBase object) { + object.buildSerialData(delegate); + } + + @Override + public void write(int b) throws IOException { + delegate.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + delegate.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + delegate.write(b, off, len); + } + + @Override + public void writeBoolean(boolean v) throws IOException { + delegate.writeBoolean(v); + } + + @Override + public void writeByte(int v) throws IOException { + delegate.writeByte(v); + } + + @Override + public void writeShort(int v) throws IOException { + delegate.writeShort(v); + } + + @Override + public void writeChar(int v) throws IOException { + delegate.writeChar(v); + } + + @Override + public void writeInt(int v) throws IOException { + delegate.writeInt(v); + } + + @Override + public void writeLong(long v) throws IOException { + delegate.writeLong(v); + } + + @Override + public void writeFloat(float v) throws IOException { + delegate.writeFloat(v); + } + + @Override + public void writeDouble(double v) throws IOException { + delegate.writeDouble(v); + } + + @Override + public void writeChars(String s) throws IOException { + delegate.writeChars(s); + } + + @Override + public void writeUTF(String s) throws IOException { + delegate.writeUTF(s); + } + + /** + * @deprecated + * This method is error-prone because it discards the high 8 bits of each char. + */ + @Deprecated + @Override + public void writeBytes(String s) throws IOException { + delegate.writeBytes(s); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectHandle.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectHandle.java new file mode 100644 index 0000000..ce9459b --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ObjectHandle.java @@ -0,0 +1,14 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +// Note: Implementing ProxyInvocationHandlerObject is not completely correct because for example +// a handle to byte[] would not be valid; but solving this in a better way is cumbersome because +// record classes cannot be subclassed +public record ObjectHandle(HandleAssignableObject object) implements ObjectBase, ProxyInvocationHandlerObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + // TODO + throw new UnsupportedOperationException(); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyInvocationHandlerObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyInvocationHandlerObject.java new file mode 100644 index 0000000..3c8da4d --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyInvocationHandlerObject.java @@ -0,0 +1,7 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +// This interface exists to make builder API easier to use by restricting valid invocation +// handler objects; it does not correspond to any serialization format structure because a +// proxy object has regular serializable class data which allows mismatching field values +public sealed interface ProxyInvocationHandlerObject extends HandleAssignableObject permits ExternalizableObject, ObjectHandle, ProxyObject, SerializableObject { +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyObject.java new file mode 100644 index 0000000..927af59 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/ProxyObject.java @@ -0,0 +1,20 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +import java.util.List; + +public record ProxyObject( + List interfaceNames, + ProxyInvocationHandlerObject invocationHandler +) implements ProxyInvocationHandlerObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + var start = objectStart.beginProxyObject(interfaceNames.toArray(String[]::new)); + + // TODO: This is not safe; just happens to work due to how the implementation works; because ProxyObjectStart + // uses dedicated object creation methods, cannot pass it to buildSerialData + invocationHandler.buildSerialData(objectStart); + return (C) start; + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializableObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializableObject.java new file mode 100644 index 0000000..ba2746c --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializableObject.java @@ -0,0 +1,30 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.serializable.SerializableObjectWithDataStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.classdata.ClassData; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +// TODO: Add type safe subclass for cases where Class is available? Could then be used for object fields to verify correct type +// Maybe not worth it +public record SerializableObject(List classData) implements ProxyInvocationHandlerObject { + public SerializableObject { + if (classData.isEmpty()) { + throw new IllegalArgumentException("List of class data must not be empty"); + } + } + + @Override + public C buildSerialData(ObjectStart objectStart) { + var start = objectStart.beginSerializableObject(); + SerializableObjectWithDataStart intermediate = null; + for (ClassData c : classData) { + intermediate = c.buildSerialData(intermediate == null ? start : intermediate); + } + assert intermediate != null; + return intermediate.endObject(); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializedField.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializedField.java new file mode 100644 index 0000000..00aea77 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/SerializedField.java @@ -0,0 +1,9 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.serializable.SerializableObjectData; +import marcono1234.serialization.serialbuilder.simplebuilder2.classdata.ObjectField; +import marcono1234.serialization.serialbuilder.simplebuilder2.classdata.PrimitiveField; + +public sealed interface SerializedField permits PrimitiveField, ObjectField { + SerializableObjectData buildSerialData(SerializableObjectData start); +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/StringObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/StringObject.java new file mode 100644 index 0000000..0212d8a --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/StringObject.java @@ -0,0 +1,10 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +public record StringObject(String s) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.string(s); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/BooleanArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/BooleanArray.java new file mode 100644 index 0000000..841220a --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/BooleanArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record BooleanArray(boolean[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ByteArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ByteArray.java new file mode 100644 index 0000000..e8f768d --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ByteArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record ByteArray(byte[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/CharArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/CharArray.java new file mode 100644 index 0000000..fe8f051 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/CharArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record CharArray(char[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/DoubleArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/DoubleArray.java new file mode 100644 index 0000000..a7d9447 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/DoubleArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record DoubleArray(double[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/FloatArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/FloatArray.java new file mode 100644 index 0000000..a84d685 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/FloatArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record FloatArray(float[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/IntArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/IntArray.java new file mode 100644 index 0000000..46d4e83 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/IntArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record IntArray(int[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/LongArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/LongArray.java new file mode 100644 index 0000000..5bdb291 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/LongArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record LongArray(long[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ObjectArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ObjectArray.java new file mode 100644 index 0000000..77c36c4 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ObjectArray.java @@ -0,0 +1,18 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +import java.util.List; + +public record ObjectArray(String arrayType, List elements) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + var start = objectStart.beginObjectArray(arrayType); + for (ObjectBase element : elements) { + start = element.buildSerialData(start); + } + return start.endArray(); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ShortArray.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ShortArray.java new file mode 100644 index 0000000..1268d76 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/array/ShortArray.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.array; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; + +public record ShortArray(short[] array) implements HandleAssignableObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.array(array); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ClassData.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ClassData.java new file mode 100644 index 0000000..993f529 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ClassData.java @@ -0,0 +1,29 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classdata; + +import marcono1234.serialization.serialbuilder.builder.api.ThrowingConsumer; +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.serializable.SerializableObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.serializable.SerializableObjectWithDataStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectDataWriter; +import marcono1234.serialization.serialbuilder.simplebuilder2.SerializedField; + +import java.util.List; + +public record ClassData( + String className, + long serialVersion, + List fields, + ThrowingConsumer dataWriter +) { + public SerializableObjectWithDataStart buildSerialData(SerializableObjectStart start) { + var classDataStart = start.beginClassData(className, serialVersion); + for (SerializedField field : fields) { + classDataStart = field.buildSerialData(classDataStart); + } + + if (dataWriter != null) { + return classDataStart.writeObjectWith(delegateWriter -> dataWriter.accept(new ObjectDataWriter(delegateWriter))).endClassData(); + } else { + return classDataStart.endClassData(); + } + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ObjectField.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ObjectField.java new file mode 100644 index 0000000..4a3dc43 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/ObjectField.java @@ -0,0 +1,18 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classdata; + +import marcono1234.serialization.serialbuilder.builder.implementation.ClassTypeNameHelper; +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.serializable.SerializableObjectData; +import marcono1234.serialization.serialbuilder.simplebuilder2.ObjectBase; +import marcono1234.serialization.serialbuilder.simplebuilder2.SerializedField; + +public record ObjectField( + String fieldName, + String fieldType, + ObjectBase object +) implements SerializedField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + var objectStart = start.beginObjectField(fieldName, fieldType); + return object.buildSerialData(objectStart).endField(); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/PrimitiveField.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/PrimitiveField.java new file mode 100644 index 0000000..020a0c5 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classdata/PrimitiveField.java @@ -0,0 +1,62 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classdata; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.serializable.SerializableObjectData; +import marcono1234.serialization.serialbuilder.simplebuilder2.SerializedField; + +public sealed interface PrimitiveField extends SerializedField { + record BooleanField(String fieldName, boolean value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveBooleanField(fieldName, value); + } + } + + record ByteField(String fieldName, byte value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveByteField(fieldName, value); + } + } + + record CharField(String fieldName, char value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveCharField(fieldName, value); + } + } + + record ShortField(String fieldName, short value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveShortField(fieldName, value); + } + } + + record IntField(String fieldName, int value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveIntField(fieldName, value); + } + } + + record LongField(String fieldName, long value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveLongField(fieldName, value); + } + } + + record FloatField(String fieldName, float value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveFloatField(fieldName, value); + } + } + + record DoubleField(String fieldName, double value) implements PrimitiveField { + @Override + public SerializableObjectData buildSerialData(SerializableObjectData start) { + return start.primitiveDoubleField(fieldName, value); + } + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ClassObject.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ClassObject.java new file mode 100644 index 0000000..584ee98 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ClassObject.java @@ -0,0 +1,6 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classobject; + +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; + +public sealed interface ClassObject extends HandleAssignableObject permits EnumClass, ExternalizableClass, NonSerializableClass, ProxyClass, SerializableClass { +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/EnumClass.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/EnumClass.java new file mode 100644 index 0000000..d6fc3b4 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/EnumClass.java @@ -0,0 +1,11 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classobject; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; + +public record EnumClass(String className) implements ClassObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.enumClass(className); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ExternalizableClass.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ExternalizableClass.java new file mode 100644 index 0000000..2175e68 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ExternalizableClass.java @@ -0,0 +1,10 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classobject; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +public record ExternalizableClass(String className, long serialVersionUID) implements ClassObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.externalizableClass(className, serialVersionUID); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/NonSerializableClass.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/NonSerializableClass.java new file mode 100644 index 0000000..126e7ca --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/NonSerializableClass.java @@ -0,0 +1,11 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classobject; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; + +public record NonSerializableClass(String className) implements ClassObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.nonSerializableClass(className); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ProxyClass.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ProxyClass.java new file mode 100644 index 0000000..71fb4d4 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/ProxyClass.java @@ -0,0 +1,12 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classobject; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; + +import java.util.List; + +public record ProxyClass(List interfaceNames) implements ClassObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.proxyClass(interfaceNames.toArray(String[]::new)); + } +} diff --git a/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/SerializableClass.java b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/SerializableClass.java new file mode 100644 index 0000000..6742ba6 --- /dev/null +++ b/serial-builder/src/main/java/marcono1234/serialization/serialbuilder/simplebuilder2/classobject/SerializableClass.java @@ -0,0 +1,11 @@ +package marcono1234.serialization.serialbuilder.simplebuilder2.classobject; + +import marcono1234.serialization.serialbuilder.simplebuilder.api.object.ObjectStart; +import marcono1234.serialization.serialbuilder.simplebuilder2.HandleAssignableObject; + +public record SerializableClass(String className, long serialVersionUID) implements ClassObject { + @Override + public C buildSerialData(ObjectStart objectStart) { + return objectStart.serializableClass(className, serialVersionUID); + } +} diff --git a/serial-builder/src/test/java/marcono1234/serialization/serialbuilder/V2Test.java b/serial-builder/src/test/java/marcono1234/serialization/serialbuilder/V2Test.java new file mode 100644 index 0000000..e85ba49 --- /dev/null +++ b/serial-builder/src/test/java/marcono1234/serialization/serialbuilder/V2Test.java @@ -0,0 +1,63 @@ +package marcono1234.serialization.serialbuilder; + +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +import static marcono1234.serialization.serialbuilder.simplebuilder2.FactoryMethods.*; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +// TODO: Use proper test class name +public class V2Test { + private static T deserialize(byte[] data) { + try (ObjectInputStream objIn = new ObjectInputStream(new ByteArrayInputStream(data))) { + @SuppressWarnings("unchecked") + T result = (T) objIn.readObject(); + return result; + } catch (IOException | ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + + private static class SerializableClass implements Serializable { + @Serial + private static final long serialVersionUID = 1L; + + public int i; + public int[] array; + public String s; + } + + @Test + void test() { + byte[] b = serializableObject( + classData( + SerializableClass.class, + List.of( + intField("i", 6), + objectField( + "array", + int[].class, + array(new int[] {1, 2, 3}) + ), + objectField( + "s", + String.class, + string("nested-test") + ) + ) + ) + ).createSerialData(); + + SerializableClass actualObject = deserialize(b); + assertEquals(6, actualObject.i); + assertArrayEquals(new int[] {1, 2, 3}, actualObject.array); + assertEquals("nested-test", actualObject.s); + } +}