mirror of
https://github.com/corda/corda.git
synced 2025-03-21 11:35:57 +00:00
ENT-2977 resolve custom serializers earlier (#4609)
* ENT-2977 resolve custom serializers earlier * Remove unnecessary import * Cache hot serialisation paths * Remove blank line
This commit is contained in:
parent
9f4c8bcea5
commit
d540aa5b17
@ -27,7 +27,18 @@ class CachingCustomSerializerRegistry(
|
||||
|
||||
private data class CustomSerializerIdentifier(val actualTypeIdentifier: TypeIdentifier, val declaredTypeIdentifier: TypeIdentifier)
|
||||
|
||||
private val customSerializersCache: MutableMap<CustomSerializerIdentifier, AMQPSerializer<Any>> = DefaultCacheProvider.createCache()
|
||||
private sealed class CustomSerializerLookupResult {
|
||||
|
||||
abstract val serializerIfFound: AMQPSerializer<Any>?
|
||||
|
||||
object None : CustomSerializerLookupResult() {
|
||||
override val serializerIfFound: AMQPSerializer<Any>? = null
|
||||
}
|
||||
|
||||
data class CustomSerializerFound(override val serializerIfFound: AMQPSerializer<Any>) : CustomSerializerLookupResult()
|
||||
}
|
||||
|
||||
private val customSerializersCache: MutableMap<CustomSerializerIdentifier, CustomSerializerLookupResult> = DefaultCacheProvider.createCache()
|
||||
private var customSerializers: List<SerializerFor> = emptyList()
|
||||
|
||||
/**
|
||||
@ -37,6 +48,11 @@ class CachingCustomSerializerRegistry(
|
||||
override fun register(customSerializer: CustomSerializer<out Any>) {
|
||||
logger.trace("action=\"Registering custom serializer\", class=\"${customSerializer.type}\"")
|
||||
|
||||
if (!customSerializersCache.isEmpty()) {
|
||||
logger.warn("Attempting to register custom serializer $customSerializer.type} in an active cache." +
|
||||
"All serializers should be registered before the cache comes into use.")
|
||||
}
|
||||
|
||||
descriptorBasedSerializerRegistry.getOrBuild(customSerializer.typeDescriptor.toString()) {
|
||||
customSerializers += customSerializer
|
||||
for (additional in customSerializer.additionalSerializers) {
|
||||
@ -49,6 +65,11 @@ class CachingCustomSerializerRegistry(
|
||||
override fun registerExternal(customSerializer: CorDappCustomSerializer) {
|
||||
logger.trace("action=\"Registering external serializer\", class=\"${customSerializer.type}\"")
|
||||
|
||||
if (!customSerializersCache.isEmpty()) {
|
||||
logger.warn("Attempting to register custom serializer ${customSerializer.type} in an active cache." +
|
||||
"All serializers must be registered before the cache comes into use.")
|
||||
}
|
||||
|
||||
descriptorBasedSerializerRegistry.getOrBuild(customSerializer.typeDescriptor.toString()) {
|
||||
customSerializers += customSerializer
|
||||
customSerializer
|
||||
@ -60,10 +81,11 @@ class CachingCustomSerializerRegistry(
|
||||
TypeIdentifier.forClass(clazz),
|
||||
TypeIdentifier.forGenericType(declaredType))
|
||||
|
||||
return customSerializersCache[typeIdentifier]
|
||||
?: doFindCustomSerializer(clazz, declaredType)?.also { serializer ->
|
||||
customSerializersCache.putIfAbsent(typeIdentifier, serializer)
|
||||
}
|
||||
return customSerializersCache.getOrPut(typeIdentifier) {
|
||||
val customSerializer = doFindCustomSerializer(clazz, declaredType)
|
||||
if (customSerializer == null) CustomSerializerLookupResult.None
|
||||
else CustomSerializerLookupResult.CustomSerializerFound(customSerializer)
|
||||
}.serializerIfFound
|
||||
}
|
||||
|
||||
private fun doFindCustomSerializer(clazz: Class<*>, declaredType: Type): AMQPSerializer<Any>? {
|
||||
|
@ -7,10 +7,8 @@ import net.corda.core.utilities.debug
|
||||
import net.corda.core.utilities.trace
|
||||
import net.corda.serialization.internal.model.*
|
||||
import org.apache.qpid.proton.amqp.Symbol
|
||||
import java.io.NotSerializableException
|
||||
import java.lang.reflect.ParameterizedType
|
||||
import java.lang.reflect.Type
|
||||
import java.lang.reflect.WildcardType
|
||||
import java.util.*
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
@ -90,7 +88,10 @@ class DefaultLocalSerializerFactory(
|
||||
val logger = contextLogger()
|
||||
}
|
||||
|
||||
private val serializersByType: MutableMap<TypeIdentifier, AMQPSerializer<Any>> = DefaultCacheProvider.createCache()
|
||||
private data class ActualAndDeclaredType(val actualType: Class<*>, val declaredType: Type)
|
||||
|
||||
private val serializersByActualAndDeclaredType: MutableMap<ActualAndDeclaredType, AMQPSerializer<Any>> = DefaultCacheProvider.createCache()
|
||||
private val serializersByTypeId: MutableMap<TypeIdentifier, AMQPSerializer<Any>> = DefaultCacheProvider.createCache()
|
||||
private val typesByName = DefaultCacheProvider.createCache<String, Optional<LocalTypeInformation>>()
|
||||
|
||||
override fun createDescriptor(typeInformation: LocalTypeInformation): Symbol =
|
||||
@ -101,10 +102,10 @@ class DefaultLocalSerializerFactory(
|
||||
override fun getTypeInformation(typeName: String): LocalTypeInformation? {
|
||||
return typesByName.getOrPut(typeName) {
|
||||
val localType = try {
|
||||
Class.forName(typeName, false, classloader)
|
||||
} catch (_: ClassNotFoundException) {
|
||||
null
|
||||
}
|
||||
Class.forName(typeName, false, classloader)
|
||||
} catch (_: ClassNotFoundException) {
|
||||
null
|
||||
}
|
||||
Optional.ofNullable(localType?.run { getTypeInformation(this) })
|
||||
}.orElse(null)
|
||||
}
|
||||
@ -112,73 +113,85 @@ class DefaultLocalSerializerFactory(
|
||||
override fun get(typeInformation: LocalTypeInformation): AMQPSerializer<Any> =
|
||||
get(typeInformation.observedType, typeInformation)
|
||||
|
||||
private fun make(typeInformation: LocalTypeInformation, build: () -> AMQPSerializer<Any>) =
|
||||
make(typeInformation.typeIdentifier, build)
|
||||
private fun makeAndCache(typeInformation: LocalTypeInformation, build: () -> AMQPSerializer<Any>) =
|
||||
makeAndCache(typeInformation.typeIdentifier, build)
|
||||
|
||||
private fun make(typeIdentifier: TypeIdentifier, build: () -> AMQPSerializer<Any>) =
|
||||
serializersByType.computeIfAbsent(typeIdentifier) { _ -> build() }
|
||||
|
||||
private fun get(declaredType: Type, localTypeInformation: LocalTypeInformation): AMQPSerializer<Any> {
|
||||
val declaredClass = declaredType.asClass()
|
||||
|
||||
// can be useful to enable but will be *extremely* chatty if you do
|
||||
logger.trace { "Get Serializer for $declaredClass ${declaredType.typeName}" }
|
||||
|
||||
return when(localTypeInformation) {
|
||||
is LocalTypeInformation.ACollection -> makeDeclaredCollection(localTypeInformation)
|
||||
is LocalTypeInformation.AMap -> makeDeclaredMap(localTypeInformation)
|
||||
is LocalTypeInformation.AnEnum -> makeDeclaredEnum(localTypeInformation, declaredType, declaredClass)
|
||||
else -> makeClassSerializer(declaredClass, declaredType, declaredType, localTypeInformation)
|
||||
}.also { serializer -> descriptorBasedSerializerRegistry[serializer.typeDescriptor.toString()] = serializer }
|
||||
}
|
||||
|
||||
private fun makeDeclaredEnum(localTypeInformation: LocalTypeInformation, declaredType: Type, declaredClass: Class<*>): AMQPSerializer<Any> =
|
||||
make(localTypeInformation) {
|
||||
whitelist.requireWhitelisted(declaredType)
|
||||
EnumSerializer(declaredType, declaredClass, this)
|
||||
private fun makeAndCache(typeIdentifier: TypeIdentifier, build: () -> AMQPSerializer<Any>) =
|
||||
serializersByTypeId.getOrPut(typeIdentifier) {
|
||||
build().also { serializer ->
|
||||
descriptorBasedSerializerRegistry[serializer.typeDescriptor.toString()] = serializer
|
||||
}
|
||||
}
|
||||
|
||||
private fun get(declaredType: Type, localTypeInformation: LocalTypeInformation): AMQPSerializer<Any> =
|
||||
serializersByTypeId.getOrPut(localTypeInformation.typeIdentifier) {
|
||||
val declaredClass = declaredType.asClass()
|
||||
|
||||
// can be useful to enable but will be *extremely* chatty if you do
|
||||
logger.trace { "Get Serializer for $declaredClass ${declaredType.typeName}" }
|
||||
customSerializerRegistry.findCustomSerializer(declaredClass, declaredType)?.apply { return@get this }
|
||||
|
||||
return when (localTypeInformation) {
|
||||
is LocalTypeInformation.ACollection -> makeDeclaredCollection(localTypeInformation)
|
||||
is LocalTypeInformation.AMap -> makeDeclaredMap(localTypeInformation)
|
||||
is LocalTypeInformation.AnEnum -> makeDeclaredEnum(localTypeInformation, declaredType, declaredClass)
|
||||
else -> makeClassSerializer(declaredClass, declaredType, localTypeInformation)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeDeclaredEnum(localTypeInformation: LocalTypeInformation, declaredType: Type, declaredClass: Class<*>): AMQPSerializer<Any> =
|
||||
makeAndCache(localTypeInformation) {
|
||||
whitelist.requireWhitelisted(declaredType)
|
||||
EnumSerializer(declaredType, declaredClass, this)
|
||||
}
|
||||
|
||||
private fun makeActualEnum(localTypeInformation: LocalTypeInformation, declaredType: Type, declaredClass: Class<*>): AMQPSerializer<Any> =
|
||||
make(localTypeInformation) {
|
||||
makeAndCache(localTypeInformation) {
|
||||
whitelist.requireWhitelisted(declaredType)
|
||||
EnumSerializer(declaredType, declaredClass, this)
|
||||
}
|
||||
|
||||
private fun makeDeclaredCollection(localTypeInformation: LocalTypeInformation.ACollection): AMQPSerializer<Any> {
|
||||
val resolved = CollectionSerializer.resolveDeclared(localTypeInformation)
|
||||
return make(resolved) {
|
||||
return makeAndCache(resolved) {
|
||||
CollectionSerializer(resolved.typeIdentifier.getLocalType(classloader) as ParameterizedType, this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeDeclaredMap(localTypeInformation: LocalTypeInformation.AMap): AMQPSerializer<Any> {
|
||||
val resolved = MapSerializer.resolveDeclared(localTypeInformation)
|
||||
return make(resolved) {
|
||||
return makeAndCache(resolved) {
|
||||
MapSerializer(resolved.typeIdentifier.getLocalType(classloader) as ParameterizedType, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun get(actualClass: Class<*>, declaredType: Type): AMQPSerializer<Any> {
|
||||
// can be useful to enable but will be *extremely* chatty if you do
|
||||
logger.trace { "Get Serializer for $actualClass ${declaredType.typeName}" }
|
||||
val actualAndDeclaredType = ActualAndDeclaredType(actualClass, declaredType)
|
||||
return serializersByActualAndDeclaredType.getOrPut(actualAndDeclaredType) {
|
||||
// can be useful to enable but will be *extremely* chatty if you do
|
||||
logger.trace { "Get Serializer for $actualClass ${declaredType.typeName}" }
|
||||
customSerializerRegistry.findCustomSerializer(actualClass, declaredType)?.apply { return@get this }
|
||||
|
||||
val declaredClass = declaredType.asClass()
|
||||
val actualType: Type = inferTypeVariables(actualClass, declaredClass, declaredType) ?: declaredType
|
||||
val declaredTypeInformation = typeModel.inspect(declaredType)
|
||||
val actualTypeInformation = typeModel.inspect(actualType)
|
||||
val declaredClass = declaredType.asClass()
|
||||
val actualType: Type = inferTypeVariables(actualClass, declaredClass, declaredType) ?: declaredType
|
||||
val declaredTypeInformation = typeModel.inspect(declaredType)
|
||||
val actualTypeInformation = typeModel.inspect(actualType)
|
||||
|
||||
return when(actualTypeInformation) {
|
||||
is LocalTypeInformation.ACollection -> makeActualCollection(actualClass,declaredTypeInformation as? LocalTypeInformation.ACollection ?: actualTypeInformation)
|
||||
is LocalTypeInformation.AMap -> makeActualMap(declaredType, actualClass,declaredTypeInformation as? LocalTypeInformation.AMap ?: actualTypeInformation)
|
||||
is LocalTypeInformation.AnEnum -> makeActualEnum(actualTypeInformation, actualType, actualClass)
|
||||
else -> makeClassSerializer(actualClass, actualType, declaredType, actualTypeInformation)
|
||||
}.also { serializer -> descriptorBasedSerializerRegistry[serializer.typeDescriptor.toString()] = serializer }
|
||||
return when (actualTypeInformation) {
|
||||
is LocalTypeInformation.ACollection -> makeActualCollection(actualClass, declaredTypeInformation as? LocalTypeInformation.ACollection
|
||||
?: actualTypeInformation)
|
||||
is LocalTypeInformation.AMap -> makeActualMap(declaredType, actualClass, declaredTypeInformation as? LocalTypeInformation.AMap
|
||||
?: actualTypeInformation)
|
||||
is LocalTypeInformation.AnEnum -> makeActualEnum(actualTypeInformation, actualType, actualClass)
|
||||
else -> makeClassSerializer(actualClass, actualType, actualTypeInformation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeActualMap(declaredType: Type, actualClass: Class<*>, typeInformation: LocalTypeInformation.AMap): AMQPSerializer<Any> {
|
||||
declaredType.asClass().checkSupportedMapType()
|
||||
val resolved = MapSerializer.resolveActual(actualClass, typeInformation)
|
||||
return make(resolved) {
|
||||
return makeAndCache(resolved) {
|
||||
MapSerializer(resolved.typeIdentifier.getLocalType(classloader) as ParameterizedType, this)
|
||||
}
|
||||
}
|
||||
@ -186,7 +199,7 @@ class DefaultLocalSerializerFactory(
|
||||
private fun makeActualCollection(actualClass: Class<*>, typeInformation: LocalTypeInformation.ACollection): AMQPSerializer<Any> {
|
||||
val resolved = CollectionSerializer.resolveActual(actualClass, typeInformation)
|
||||
|
||||
return serializersByType.computeIfAbsent(resolved.typeIdentifier) {
|
||||
return makeAndCache(resolved) {
|
||||
CollectionSerializer(resolved.typeIdentifier.getLocalType(classloader) as ParameterizedType, this)
|
||||
}
|
||||
}
|
||||
@ -194,9 +207,8 @@ class DefaultLocalSerializerFactory(
|
||||
private fun makeClassSerializer(
|
||||
clazz: Class<*>,
|
||||
type: Type,
|
||||
declaredType: Type,
|
||||
typeInformation: LocalTypeInformation
|
||||
): AMQPSerializer<Any> = make(typeInformation) {
|
||||
): AMQPSerializer<Any> = makeAndCache(typeInformation) {
|
||||
logger.debug { "class=${clazz.simpleName}, type=$type is a composite type" }
|
||||
when {
|
||||
clazz.isSynthetic -> // Explicitly ban synthetic classes, we have no way of recreating them when deserializing. This also
|
||||
@ -205,8 +217,7 @@ class DefaultLocalSerializerFactory(
|
||||
type,
|
||||
"Serializer does not support synthetic classes")
|
||||
AMQPTypeIdentifiers.isPrimitive(typeInformation.typeIdentifier) -> AMQPPrimitiveSerializer(clazz)
|
||||
else -> customSerializerRegistry.findCustomSerializer(clazz, declaredType) ?:
|
||||
makeNonCustomSerializer(type, typeInformation, clazz)
|
||||
else -> makeNonCustomSerializer(type, typeInformation, clazz)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user