diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/CustomSerializer.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/CustomSerializer.kt index 8eb4c6c60a..471546369e 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/CustomSerializer.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/CustomSerializer.kt @@ -30,7 +30,8 @@ abstract class CustomSerializer : AMQPSerializer, SerializerFor { open val additionalSerializers: Iterable> = emptyList() /** - * This custom serializer is also allowed to deserialize these classes. + * This custom serializer is also allowed to deserialize these classes. This allows us + * to deserialize objects into completely different types, e.g. `A` -> `sandbox.A`. */ open val deserializationAliases: Set> = emptySet() @@ -57,6 +58,12 @@ abstract class CustomSerializer : AMQPSerializer, SerializerFor { abstract fun writeDescribedObject(obj: T, data: Data, type: Type, output: SerializationOutput, context: SerializationContext) + /** + * [CustomSerializerRegistry.findCustomSerializer] will invoke this method on the [CustomSerializer] + * that it selects to give that serializer an opportunity to customise its behaviour. The serializer + * can also return `null` here, in which case [CustomSerializerRegistry] will proceed as if no + * serializer is available for [declaredType]. + */ open fun specialiseFor(declaredType: Type): AMQPSerializer? = this /** diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/Schema.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/Schema.kt index 26dc084587..36ac18bfe6 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/Schema.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/Schema.kt @@ -18,6 +18,11 @@ val amqpMagic = CordaSerializationMagic("corda".toByteArray() + byteArrayOf(1, 0 fun typeDescriptorFor(typeId: TypeIdentifier): Symbol = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${AMQPTypeIdentifiers.nameForType(typeId)}") fun typeDescriptorFor(type: Type): Symbol = typeDescriptorFor(forGenericType(type)) +/** + * Repackages a naked, non-primitive [obj] as a [DescribedType]. If [obj] is primitive, [Binary] or already + * an instance of [DescribedType]] then it is returned unchanged. This allows Corda to search for a serializer + * capable of handling instances of [type]. + */ fun redescribe(obj: Any?, type: Type): Any? { return if (obj == null || obj is DescribedType || obj is Binary || forGenericType(type).run { isPrimitive(this) || this == TopType }) { obj diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt index 274cd50dda..2697b107a8 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/model/TypeIdentifier.kt @@ -210,7 +210,8 @@ sealed class TypeIdentifier { override fun getLocalType(classLoader: ClassLoader): Type { // We need to invoke ClassLoader.loadClass() directly, because // the JVM will complain if Class.forName() returns a class - // that has a name other than the requested one. + // that has a name other than the requested one. This will happen + // for "transformative" class loaders, i.e. `A` -> `sandbox.A`. val rawType = classLoader.loadClass(name) if (rawType.typeParameters.size != parameters.size) { throw IncompatibleTypeIdentifierException(