diff --git a/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt b/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt index 4020ca5cc5..66f15ba7b2 100644 --- a/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt +++ b/core/src/main/kotlin/net/corda/core/serialization/amqp/PropertySerializer.kt @@ -55,8 +55,10 @@ sealed class PropertySerializer(val name: String, val readMethod: Method, val re companion object { fun make(name: String, readMethod: Method, resolvedType: Type, factory: SerializerFactory): PropertySerializer { if (SerializerFactory.isPrimitive(resolvedType)) { - // This is a little inefficient for performance since it does a runtime check of type. We could do build time check with lots of subclasses here. - return AMQPPrimitivePropertySerializer(name, readMethod, resolvedType) + return when(resolvedType) { + Char::class.java, Character::class.java -> AMQPCharPropertySerializer(name, readMethod) + else -> AMQPPrimitivePropertySerializer(name, readMethod, resolvedType) + } } else { return DescribedTypePropertySerializer(name, readMethod, resolvedType) { factory.get(null, resolvedType) } } @@ -86,10 +88,9 @@ sealed class PropertySerializer(val name: String, val readMethod: Method, val re } /** - * A property serializer for an AMQP primitive type (Int, String, etc). + * A property serializer for most AMQP primitive type (Int, String, etc). */ class AMQPPrimitivePropertySerializer(name: String, readMethod: Method, resolvedType: Type) : PropertySerializer(name, readMethod, resolvedType) { - override fun writeClassInfo(output: SerializationOutput) {} override fun readProperty(obj: Any?, schema: Schema, input: DeserializationInput): Any? { @@ -105,5 +106,21 @@ sealed class PropertySerializer(val name: String, val readMethod: Method, val re } } } + + /** + * A property serializer for the AMQP char type, needed as a specialisation as the underlaying + * value of the character is stored in numeric ASCII form and on deserialisation requires explicit + * casting back to a char otherwise it's treated as an Integer and TypeMismatchs occur + */ + class AMQPCharPropertySerializer(name: String, readMethod: Method) : + PropertySerializer(name, readMethod, Char::class.java) { + override fun writeClassInfo(output: SerializationOutput) {} + + override fun readProperty(obj: Any?, schema: Schema, input: DeserializationInput) = (obj as Int).toChar() + + override fun writeProperty(obj: Any?, data: Data, output: SerializationOutput) { + data.putObject(readMethod.invoke(obj)) + } + } } diff --git a/core/src/test/kotlin/net/corda/core/serialization/amqp/DeserializeSimpleTypesTests.kt b/core/src/test/kotlin/net/corda/core/serialization/amqp/DeserializeSimpleTypesTests.kt new file mode 100644 index 0000000000..d9bdcaf1e9 --- /dev/null +++ b/core/src/test/kotlin/net/corda/core/serialization/amqp/DeserializeSimpleTypesTests.kt @@ -0,0 +1,34 @@ +package net.corda.core.serialization.amqp + +import org.junit.Test +import java.io.ByteArrayOutputStream +import kotlin.test.assertEquals + +/** + * Prior to certain fixes being made within the [PropertySerializaer] classes these simple + * deserialization operations would've blown up with type mismatch errors where the deserlized + * char property of the class would've been treated as an Integer and given to the constructor + * as such + */ +class DeserializeSimpleTypesTests { + @Test + fun testChar() { + data class C(val c: Char) + val c = C('c') + val serialisedC = SerializationOutput().serialize(c) + val deserializedC = DeserializationInput().deserialize(serialisedC) + + assertEquals(c.c, deserializedC.c) + } + + @Test + fun testCharacter() { + data class C(val c: Character) + val c = C(Character ('c')) + val serialisedC = SerializationOutput().serialize(c) + val deserializedC = DeserializationInput().deserialize(serialisedC) + + assertEquals(c.c, deserializedC.c) + } +} +