diff --git a/serial/src/main/java/io/smallrye/serial/SerializedArrayClass.java b/serial/src/main/java/io/smallrye/serial/SerializedArrayClass.java index 3fdd17c..af5fb23 100644 --- a/serial/src/main/java/io/smallrye/serial/SerializedArrayClass.java +++ b/serial/src/main/java/io/smallrye/serial/SerializedArrayClass.java @@ -58,6 +58,11 @@ public SerializedArrayClass(final ClassDesc classDesc, final Serialized classLoa this.componentType = Assert.checkNotNullParam("componentType", componentType); } + @Override + final String computeName() { + return descriptorString().replace('/', '.'); + } + /** * {@return the class descriptor of the array's component type (not {@code null})} * For multi-dimensional arrays, this is itself a {@code SerializedArrayClass}. diff --git a/serial/src/main/java/io/smallrye/serial/SerializedClass.java b/serial/src/main/java/io/smallrye/serial/SerializedClass.java index 33697c6..4271f2d 100644 --- a/serial/src/main/java/io/smallrye/serial/SerializedClass.java +++ b/serial/src/main/java/io/smallrye/serial/SerializedClass.java @@ -3,7 +3,6 @@ import java.lang.constant.ClassDesc; import io.smallrye.common.constraint.Assert; -import io.smallrye.serial.impl.Util; /** * The serialized representation of a {@link Class}. @@ -52,7 +51,7 @@ public String descriptorString() { * {@return the name of the serialized class in {@link Class#getName()} format (not {@code null})} * The name is lazily computed from the {@linkplain #descriptor() class descriptor} and cached. */ - public String name() { + public final String name() { String n = name; if (n == null) { name = n = computeName(); @@ -62,15 +61,13 @@ public String name() { /** * Compute the {@link Class#getName()}-format name from the stored class descriptor. + * Subclasses with non-reference-type descriptors override this method. + * + * @return the computed name (not {@code null}) */ - private String computeName() { + String computeName() { String desc = classDesc.descriptorString(); - char typeCode = desc.charAt(0); - return switch (typeCode) { - case '[' -> desc.replace('/', '.'); - case 'L' -> desc.substring(1, desc.length() - 1).replace('/', '.'); - default -> Util.primitiveTypeName(typeCode); - }; + return desc.substring(1, desc.length() - 1).replace('/', '.'); } /** diff --git a/serial/src/main/java/io/smallrye/serial/SerializedPrimitiveClass.java b/serial/src/main/java/io/smallrye/serial/SerializedPrimitiveClass.java index e1dec4f..daa3712 100644 --- a/serial/src/main/java/io/smallrye/serial/SerializedPrimitiveClass.java +++ b/serial/src/main/java/io/smallrye/serial/SerializedPrimitiveClass.java @@ -2,6 +2,9 @@ import java.lang.constant.ClassDesc; +import io.smallrye.serial.impl.Primitive; +import io.smallrye.serial.impl.Util; + /** * The serialized representation of a primitive type or {@code void}. *

@@ -43,6 +46,11 @@ private SerializedPrimitiveClass(final ClassDesc classDesc) { super(classDesc, SerializedKnownClassLoader.forBootClassLoader()); } + @Override + final String computeName() { + return Util.primitiveTypeName(descriptorString().charAt(0)); + } + /** * Return the singleton for the given primitive class descriptor. * @@ -63,17 +71,10 @@ public static SerializedPrimitiveClass of(ClassDesc classDesc) { * @throws IllegalArgumentException if the type code is not a recognized primitive type code */ public static SerializedPrimitiveClass of(char typeCode) { - return switch (typeCode) { - case 'Z' -> BOOLEAN; - case 'B' -> BYTE; - case 'C' -> CHAR; - case 'S' -> SHORT; - case 'I' -> INT; - case 'J' -> LONG; - case 'F' -> FLOAT; - case 'D' -> DOUBLE; - case 'V' -> VOID; - default -> throw new IllegalArgumentException("Not a primitive type code: " + typeCode); - }; + Primitive prim = Primitive.forTypeCode(typeCode); + if (prim == null) { + throw new IllegalArgumentException("Not a primitive type code: " + typeCode); + } + return prim.serializedClass(); } } diff --git a/serial/src/main/java/io/smallrye/serial/impl/Primitive.java b/serial/src/main/java/io/smallrye/serial/impl/Primitive.java index c1db426..703a24e 100644 --- a/serial/src/main/java/io/smallrye/serial/impl/Primitive.java +++ b/serial/src/main/java/io/smallrye/serial/impl/Primitive.java @@ -3,29 +3,31 @@ import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; +import io.smallrye.serial.SerializedPrimitiveClass; + /** * The primitive types of the Java language, with associated metadata * for serialization operations. */ public enum Primitive { /** The {@code boolean} type. */ - BOOLEAN('Z', "boolean", 1, 1, ConstantDescs.CD_boolean), + BOOLEAN('Z', "boolean", 1, 1, ConstantDescs.CD_boolean, SerializedPrimitiveClass.BOOLEAN), /** The {@code byte} type. */ - BYTE('B', "byte", 1, 1, ConstantDescs.CD_byte), + BYTE('B', "byte", 1, 1, ConstantDescs.CD_byte, SerializedPrimitiveClass.BYTE), /** The {@code char} type. */ - CHAR('C', "char", 2, 1, ConstantDescs.CD_char), + CHAR('C', "char", 2, 1, ConstantDescs.CD_char, SerializedPrimitiveClass.CHAR), /** The {@code short} type. */ - SHORT('S', "short", 2, 1, ConstantDescs.CD_short), + SHORT('S', "short", 2, 1, ConstantDescs.CD_short, SerializedPrimitiveClass.SHORT), /** The {@code int} type. */ - INT('I', "int", 4, 1, ConstantDescs.CD_int), + INT('I', "int", 4, 1, ConstantDescs.CD_int, SerializedPrimitiveClass.INT), /** The {@code long} type. */ - LONG('J', "long", 8, 2, ConstantDescs.CD_long), + LONG('J', "long", 8, 2, ConstantDescs.CD_long, SerializedPrimitiveClass.LONG), /** The {@code float} type. */ - FLOAT('F', "float", 4, 1, ConstantDescs.CD_float), + FLOAT('F', "float", 4, 1, ConstantDescs.CD_float, SerializedPrimitiveClass.FLOAT), /** The {@code double} type. */ - DOUBLE('D', "double", 8, 2, ConstantDescs.CD_double), + DOUBLE('D', "double", 8, 2, ConstantDescs.CD_double, SerializedPrimitiveClass.DOUBLE), /** The {@code void} type. */ - VOID('V', "void", 0, 0, ConstantDescs.CD_void), + VOID('V', "void", 0, 0, ConstantDescs.CD_void, SerializedPrimitiveClass.VOID), ; private final char typeCode; @@ -33,13 +35,16 @@ public enum Primitive { private final int byteSize; private final int slotSize; private final ClassDesc classDesc; + private final SerializedPrimitiveClass serializedClass; - Primitive(char typeCode, String typeName, int byteSize, int slotSize, ClassDesc classDesc) { + Primitive(char typeCode, String typeName, int byteSize, int slotSize, ClassDesc classDesc, + final SerializedPrimitiveClass serializedClass) { this.typeCode = typeCode; this.typeName = typeName; this.byteSize = byteSize; this.slotSize = slotSize; this.classDesc = classDesc; + this.serializedClass = serializedClass; } /** @@ -120,4 +125,11 @@ public static Primitive forClassDesc(ClassDesc classDesc) { public static Primitive forClass(Class type) { return forClassDesc(Util.classDesc(type)); } + + /** + * {@return the serialized primitive class for this primitive type} + */ + public SerializedPrimitiveClass serializedClass() { + return serializedClass; + } } diff --git a/serial/src/test/java/io/smallrye/serial/ClassNameTest.java b/serial/src/test/java/io/smallrye/serial/ClassNameTest.java new file mode 100644 index 0000000..00944d1 --- /dev/null +++ b/serial/src/test/java/io/smallrye/serial/ClassNameTest.java @@ -0,0 +1,166 @@ +package io.smallrye.serial; + +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; + +import org.junit.jupiter.api.Test; + +/** + * Tests that {@link SerializedClass#name()} matches {@link Class#getName()} for + * all class descriptor types: primitives, arrays, regular classes, and nested types. + */ +class ClassNameTest { + + private final SerialContext ctx = SerialContext.builder().addDefaultProviders().build(); + private final Serializer ser = ctx.createSerializer(); + + // ---- Primitive types ---- + + @Test + void booleanName() { + assertEquals(boolean.class.getName(), SerializedPrimitiveClass.BOOLEAN.name()); + } + + @Test + void byteName() { + assertEquals(byte.class.getName(), SerializedPrimitiveClass.BYTE.name()); + } + + @Test + void charName() { + assertEquals(char.class.getName(), SerializedPrimitiveClass.CHAR.name()); + } + + @Test + void shortName() { + assertEquals(short.class.getName(), SerializedPrimitiveClass.SHORT.name()); + } + + @Test + void intName() { + assertEquals(int.class.getName(), SerializedPrimitiveClass.INT.name()); + } + + @Test + void longName() { + assertEquals(long.class.getName(), SerializedPrimitiveClass.LONG.name()); + } + + @Test + void floatName() { + assertEquals(float.class.getName(), SerializedPrimitiveClass.FLOAT.name()); + } + + @Test + void doubleName() { + assertEquals(double.class.getName(), SerializedPrimitiveClass.DOUBLE.name()); + } + + @Test + void voidName() { + assertEquals(void.class.getName(), SerializedPrimitiveClass.VOID.name()); + } + + // ---- Primitive array types ---- + + @Test + void booleanArrayName() { + assertEquals(boolean[].class.getName(), SerializedArrayClass.BOOLEAN_ARRAY.name()); + } + + @Test + void byteArrayName() { + assertEquals(byte[].class.getName(), SerializedArrayClass.BYTE_ARRAY.name()); + } + + @Test + void charArrayName() { + assertEquals(char[].class.getName(), SerializedArrayClass.CHAR_ARRAY.name()); + } + + @Test + void shortArrayName() { + assertEquals(short[].class.getName(), SerializedArrayClass.SHORT_ARRAY.name()); + } + + @Test + void intArrayName() { + assertEquals(int[].class.getName(), SerializedArrayClass.INT_ARRAY.name()); + } + + @Test + void longArrayName() { + assertEquals(long[].class.getName(), SerializedArrayClass.LONG_ARRAY.name()); + } + + @Test + void floatArrayName() { + assertEquals(float[].class.getName(), SerializedArrayClass.FLOAT_ARRAY.name()); + } + + @Test + void doubleArrayName() { + assertEquals(double[].class.getName(), SerializedArrayClass.DOUBLE_ARRAY.name()); + } + + // ---- Object array types ---- + + @Test + void stringArrayName() throws IOException { + Serialized s = ser.serialize(String[].class); + assertInstanceOf(SerializedArrayClass.class, s); + assertEquals(String[].class.getName(), ((SerializedClass) s).name()); + } + + @Test + void nestedObjectArrayName() throws IOException { + Serialized s = ser.serialize(String[][].class); + assertInstanceOf(SerializedArrayClass.class, s); + assertEquals(String[][].class.getName(), ((SerializedClass) s).name()); + } + + @Test + void intMultiDimArrayName() throws IOException { + Serialized s = ser.serialize(int[][].class); + assertInstanceOf(SerializedArrayClass.class, s); + assertEquals(int[][].class.getName(), ((SerializedClass) s).name()); + } + + // ---- Reference types ---- + + @Test + void regularClassName() throws IOException { + Serialized s = ser.serialize(String.class); + assertInstanceOf(SerializedClass.class, s); + assertEquals(String.class.getName(), ((SerializedClass) s).name()); + } + + @Test + void innerClassName() throws IOException { + Serialized s = ser.serialize(java.util.Map.Entry.class); + assertInstanceOf(SerializedClass.class, s); + assertEquals(java.util.Map.Entry.class.getName(), ((SerializedClass) s).name()); + } + + @Test + void serializableClassName() throws IOException { + Serialized s = ser.serialize(java.util.ArrayList.class); + assertInstanceOf(SerializedSerializableClass.class, s); + assertEquals(java.util.ArrayList.class.getName(), ((SerializedClass) s).name()); + } + + @Test + void enumClassName() throws IOException { + Serialized s = ser.serialize(Thread.State.class); + assertInstanceOf(SerializedEnumClass.class, s); + assertEquals(Thread.State.class.getName(), ((SerializedClass) s).name()); + } + + @Test + void nonSerializableClassName() throws IOException { + Serialized s = ser.serialize(Thread.class); + assertInstanceOf(SerializedNonSerializableClass.class, s); + assertEquals(Thread.class.getName(), ((SerializedClass) s).name()); + } +}