diff --git a/serialization-deterministic/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt b/serialization-deterministic/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt index 2b1d66ab76..19a59bc9ba 100644 --- a/serialization-deterministic/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt +++ b/serialization-deterministic/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt @@ -13,11 +13,16 @@ import net.corda.serialization.internal.carpenter.Schema @Suppress("UNUSED") fun createSerializerFactoryFactory(): SerializerFactoryFactory = DeterministicSerializerFactoryFactory() +/** + * Creates a [ClassCarpenter] suitable for the DJVM, i.e. one that doesn't work. + */ +fun createClassCarpenter(context: SerializationContext): ClassCarpenter = DummyClassCarpenter(context.whitelist, context.deserializationClassLoader) + private class DeterministicSerializerFactoryFactory : SerializerFactoryFactory { override fun make(context: SerializationContext) = SerializerFactoryBuilder.build( whitelist = context.whitelist, - classCarpenter = DummyClassCarpenter(context.whitelist, context.deserializationClassLoader)) + classCarpenter = createClassCarpenter(context)) } private class DummyClassCarpenter( diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt index 878a294695..071dbf74b7 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/AMQPSerializerFactories.kt @@ -3,14 +3,21 @@ package net.corda.serialization.internal.amqp import net.corda.core.serialization.SerializationContext +import net.corda.serialization.internal.carpenter.ClassCarpenter import net.corda.serialization.internal.carpenter.ClassCarpenterImpl fun createSerializerFactoryFactory(): SerializerFactoryFactory = SerializerFactoryFactoryImpl() +fun createClassCarpenter(context: SerializationContext): ClassCarpenter = ClassCarpenterImpl( + whitelist = context.whitelist, + cl = context.deserializationClassLoader, + lenient = context.lenientCarpenterEnabled +) + open class SerializerFactoryFactoryImpl : SerializerFactoryFactory { override fun make(context: SerializationContext): SerializerFactory { return SerializerFactoryBuilder.build(context.whitelist, - ClassCarpenterImpl(context.whitelist, context.deserializationClassLoader, context.lenientCarpenterEnabled), + createClassCarpenter(context), mustPreserveDataWhenEvolving = context.preventDataLoss ) } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializerFactory.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializerFactory.kt index 8821860355..4755289cf6 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializerFactory.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/EvolutionSerializerFactory.kt @@ -17,6 +17,13 @@ interface EvolutionSerializerFactory { fun getEvolutionSerializer( remote: RemoteTypeInformation, local: LocalTypeInformation): AMQPSerializer? + + /** + * A mapping between Java object types and their equivalent Java primitive types. + * Predominantly for the sake of the DJVM sandbox where e.g. `char` will map to + * sandbox.java.lang.Character instead of java.lang.Character. + */ + val primitiveTypes: Map, Class<*>> } class EvolutionSerializationException(remoteTypeInformation: RemoteTypeInformation, reason: String) @@ -32,7 +39,9 @@ class EvolutionSerializationException(remoteTypeInformation: RemoteTypeInformati class DefaultEvolutionSerializerFactory( private val localSerializerFactory: LocalSerializerFactory, private val classLoader: ClassLoader, - private val mustPreserveDataWhenEvolving: Boolean): EvolutionSerializerFactory { + private val mustPreserveDataWhenEvolving: Boolean, + override val primitiveTypes: Map, Class<*>> +): EvolutionSerializerFactory { override fun getEvolutionSerializer(remote: RemoteTypeInformation, local: LocalTypeInformation): AMQPSerializer? = @@ -77,7 +86,7 @@ class DefaultEvolutionSerializerFactory( val localClass = localProperty.type.observedType.asClass() val remoteClass = remoteProperty.type.typeIdentifier.getLocalType(classLoader).asClass() - if (!localClass.isAssignableFrom(remoteClass) && remoteClass != localClass.kotlin.javaPrimitiveType) { + if (!localClass.isAssignableFrom(remoteClass) && remoteClass != primitiveTypes[localClass]) { throw EvolutionSerializationException(this, "Local type $localClass of property $name is not assignable from remote type $remoteClass") } diff --git a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactoryBuilder.kt b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactoryBuilder.kt index 82de1c6c7c..1af772c712 100644 --- a/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactoryBuilder.kt +++ b/serialization/src/main/kotlin/net/corda/serialization/internal/amqp/SerializerFactoryBuilder.kt @@ -7,9 +7,24 @@ import net.corda.serialization.internal.carpenter.ClassCarpenter import net.corda.serialization.internal.carpenter.ClassCarpenterImpl import net.corda.serialization.internal.model.* import java.io.NotSerializableException +import java.util.Collections.unmodifiableMap @KeepForDJVM object SerializerFactoryBuilder { + /** + * The standard mapping of Java object types to Java primitive types. + * The DJVM will need to override these, but probably not anyone else. + */ + private val javaPrimitiveTypes: Map, Class<*>> = unmodifiableMap(mapOf?, Class?>( + Boolean::class.javaObjectType to Boolean::class.javaPrimitiveType, + Byte::class.javaObjectType to Byte::class.javaPrimitiveType, + Char::class.javaObjectType to Char::class.javaPrimitiveType, + Double::class.javaObjectType to Double::class.javaPrimitiveType, + Float::class.javaObjectType to Float::class.javaPrimitiveType, + Int::class.javaObjectType to Int::class.javaPrimitiveType, + Long::class.javaObjectType to Long::class.javaPrimitiveType, + Short::class.javaObjectType to Short::class.javaPrimitiveType + )) as Map, Class<*>> @JvmStatic fun build(whitelist: ClassWhitelist, classCarpenter: ClassCarpenter): SerializerFactory { @@ -99,7 +114,8 @@ object SerializerFactoryBuilder { val evolutionSerializerFactory = if (allowEvolution) DefaultEvolutionSerializerFactory( localSerializerFactory, classCarpenter.classloader, - mustPreserveDataWhenEvolving + mustPreserveDataWhenEvolving, + javaPrimitiveTypes ) else NoEvolutionSerializerFactory val remoteSerializerFactory = DefaultRemoteSerializerFactory( @@ -127,4 +143,6 @@ Local: ${localTypeInformation.prettyPrint(false)} """) } + + override val primitiveTypes: Map, Class<*>> = emptyMap() } \ No newline at end of file