Allow custom serializers to be registered with type aliases for deserializing.

This commit is contained in:
Chris Rankin 2019-08-11 23:32:35 +01:00
parent 2dd1e21404
commit 8f0c7c947a
5 changed files with 22 additions and 10 deletions

View File

@ -29,6 +29,10 @@ abstract class CustomSerializer<T : Any> : AMQPSerializer<T>, SerializerFor {
*/
open val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList()
/**
* This custom serializer is also allowed to deserialize these classes.
*/
open val deserializationAliases: Set<Class<*>> = emptySet()
protected abstract val descriptor: Descriptor
/**
@ -110,7 +114,7 @@ abstract class CustomSerializer<T : Any> : AMQPSerializer<T>, SerializerFor {
*/
abstract class CustomSerializerImp<T : Any>(protected val clazz: Class<T>, protected val withInheritance: Boolean) : CustomSerializer<T>() {
override val type: Type get() = clazz
override val typeDescriptor: Symbol = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${AMQPTypeIdentifiers.nameForType(clazz)}")
override val typeDescriptor: Symbol = typeDescriptorFor(clazz)
override fun writeClassInfo(output: SerializationOutput) {}
override val descriptor: Descriptor = Descriptor(typeDescriptor)
override fun isSerializerFor(clazz: Class<*>): Boolean = if (withInheritance) this.clazz.isAssignableFrom(clazz) else this.clazz == clazz

View File

@ -84,7 +84,7 @@ class CachingCustomSerializerRegistry(
}
private val customSerializersCache: MutableMap<CustomSerializerIdentifier, CustomSerializerLookupResult> = DefaultCacheProvider.createCache()
private var customSerializers: List<SerializerFor> = emptyList()
private val customSerializers: MutableList<SerializerFor> = mutableListOf()
/**
* Register a custom serializer for any type that cannot be serialized or deserialized by the default serializer
@ -93,7 +93,7 @@ class CachingCustomSerializerRegistry(
override fun register(customSerializer: CustomSerializer<out Any>) {
logger.trace("action=\"Registering custom serializer\", class=\"${customSerializer.type}\"")
if (!customSerializersCache.isEmpty()) {
if (customSerializersCache.isNotEmpty()) {
logger.warn("Attempting to register custom serializer $customSerializer.type} in an active cache." +
"All serializers should be registered before the cache comes into use.")
}
@ -103,14 +103,23 @@ class CachingCustomSerializerRegistry(
for (additional in customSerializer.additionalSerializers) {
register(additional)
}
for (alias in customSerializer.deserializationAliases) {
val aliasDescriptor = typeDescriptorFor(alias)
if (aliasDescriptor != customSerializer.typeDescriptor) {
descriptorBasedSerializerRegistry[aliasDescriptor.toString()] = customSerializer
}
}
customSerializer
}
}
override fun registerExternal(customSerializer: CorDappCustomSerializer) {
logger.trace("action=\"Registering external serializer\", class=\"${customSerializer.type}\"")
if (!customSerializersCache.isEmpty()) {
if (customSerializersCache.isNotEmpty()) {
logger.warn("Attempting to register custom serializer ${customSerializer.type} in an active cache." +
"All serializers must be registered before the cache comes into use.")
}

View File

@ -9,12 +9,13 @@ import org.apache.qpid.proton.amqp.UnsignedInteger
import org.apache.qpid.proton.amqp.UnsignedLong
import org.apache.qpid.proton.codec.DescribedTypeConstructor
import java.io.NotSerializableException
import net.corda.serialization.internal.carpenter.Field as CarpenterField
import net.corda.serialization.internal.carpenter.Schema as CarpenterSchema
import java.lang.reflect.Type
const val DESCRIPTOR_DOMAIN: String = "net.corda"
val amqpMagic = CordaSerializationMagic("corda".toByteArray() + byteArrayOf(1, 0))
fun typeDescriptorFor(type: Type): Symbol = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${AMQPTypeIdentifiers.nameForType(type)}")
/**
* This and the classes below are OO representations of the AMQP XML schema described in the specification. Their
* [toString] representations generate the associated XML form.

View File

@ -92,7 +92,7 @@ object SerializerFactoryBuilder {
customSerializerRegistry,
onlyCustomSerializers)
val typeLoader = ClassCarpentingTypeLoader(
val typeLoader: TypeLoader = ClassCarpentingTypeLoader(
SchemaBuildingRemoteTypeCarpenter(classCarpenter),
classCarpenter.classloader)

View File

@ -1,7 +1,5 @@
package net.corda.serialization.internal.model
import net.corda.core.serialization.ClassWhitelist
import net.corda.serialization.internal.amqp.*
import java.lang.reflect.*
/**
@ -54,7 +52,7 @@ class ConfigurableLocalTypeModel(private val typeModelConfiguration: LocalTypeMo
private val typeInformationCache = DefaultCacheProvider.createCache<TypeIdentifier, LocalTypeInformation>()
/**
* We need to provide the [TypeInformationBuilder] with a temporary local cache, so that it doesn't leak
* We need to provide the [LocalTypeInformationBuilder] with a temporary local cache, so that it doesn't leak
* [LocalTypeInformation] with unpatched cycles into the global cache where other threads can access them
* before we've patched the cycles up.
*/