From 139eef2ccb6459b6ab0f5130216a85615657dcf5 Mon Sep 17 00:00:00 2001 From: Katelyn Baker Date: Tue, 8 Aug 2017 15:35:55 +0100 Subject: [PATCH] Move AMQP serializer toward the new common abstract itnerface Allow unique serializer factories to be created per unique set of WhiteList / Class Loader pair. Remove default consruction of the SerializerFactory to force use of the FactoryFactory to get the generic factory and thus access to it's ClassLoader --- .../serialization/AMQPSerializationScheme.kt | 8 +- .../serialization/KryoAMQPSerializer.kt | 3 +- .../serialization/amqp/CustomSerializer.kt | 6 +- .../amqp/DeserializationInput.kt | 2 +- .../serialization/amqp/SerializationOutput.kt | 2 +- .../serialization/amqp/SerializerFactory.kt | 31 +++--- .../amqp/SerializerFactoryFactory.kt | 22 +++++ .../carpenter/AMQPSchemaExtensions.kt | 61 ++++-------- .../serialization/carpenter/ClassCarpenter.kt | 7 +- .../serialization/carpenter/MetaCarpenter.kt | 4 +- .../serialization/amqp/AMQPTestUtils.kt | 2 +- .../amqp/DeserializeAndReturnEnvelopeTests.kt | 4 +- ...erializeNeedingCarpentrySimpleTypesTest.kt | 57 ++++++----- .../amqp/DeserializeNeedingCarpentryTests.kt | 70 ++++++-------- .../amqp/JavaSerializationOutputTests.java | 3 +- .../amqp/SerializationOutputTests.kt | 94 +++++++++---------- .../carpenter/ClassCarpenterTestUtils.kt | 4 +- ...berCompositeSchemaToClassCarpenterTests.kt | 14 +-- .../InheritanceSchemaToClassCarpenterTests.kt | 26 ++--- ...berCompositeSchemaToClassCarpenterTests.kt | 10 +- ...berCompositeSchemaToClassCarpenterTests.kt | 30 ++++-- 21 files changed, 241 insertions(+), 219 deletions(-) create mode 100644 node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactoryFactory.kt diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/AMQPSerializationScheme.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/AMQPSerializationScheme.kt index 3d1ca75f34..5e5186c343 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/AMQPSerializationScheme.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/AMQPSerializationScheme.kt @@ -41,11 +41,17 @@ abstract class AbstractAMQPSerializationScheme : SerializationScheme { rpcClientSerializerFactory(context) SerializationContext.UseCase.RPCServer -> rpcServerSerializerFactory(context) - else -> SerializerFactory(context.whitelist) // TODO pass class loader also + else -> SerializerFactory(context.whitelist, context.deserializationClassLoader) } }.also { registerCustomSerializers(it) } } + fun getSerializerFactory(): SerializerFactory { + return serializerFactoriesForContexts.computeIfAbsent(Pair(AllWhitelist, deserializationClassLoader)) { + SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + } + } + override fun deserialize(byteSequence: ByteSequence, clazz: Class, context: SerializationContext): T { val serializerFactory = getSerializerFactory(context) return DeserializationInput(serializerFactory).deserialize(byteSequence, clazz) diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/KryoAMQPSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/KryoAMQPSerializer.kt index 16dec8a83e..dae649b285 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/KryoAMQPSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/KryoAMQPSerializer.kt @@ -12,6 +12,7 @@ import net.corda.nodeapi.internal.serialization.amqp.AmqpHeaderV1_0 import net.corda.nodeapi.internal.serialization.amqp.DeserializationInput import net.corda.nodeapi.internal.serialization.amqp.SerializationOutput import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory +import net.corda.nodeapi.internal.serialization.amqp.SerializerFactoryFactory /** * This [Kryo] custom [Serializer] switches the object graph of anything annotated with `@CordaSerializable` @@ -34,4 +35,4 @@ class KryoAMQPSerializer(val serializationFactory: SerializationFactory, val ser input.readBytes(allBytes, peekedBytes.size, size - peekedBytes.size) return serializationFactory.deserialize(allBytes.sequence(), type, serializationContext) } -} \ No newline at end of file +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/CustomSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/CustomSerializer.kt index 58752b0ecc..51911f2d24 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/CustomSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/CustomSerializer.kt @@ -151,8 +151,10 @@ abstract class CustomSerializer : AMQPSerializer { * @param unmake A lambda that extracts the string value for an instance, that defaults to the [toString] method. */ abstract class ToString(clazz: Class, withInheritance: Boolean = false, - private val maker: (String) -> T = clazz.getConstructor(String::class.java).let { `constructor` -> { string -> `constructor`.newInstance(string) } }, - private val unmaker: (T) -> String = { obj -> obj.toString() }) : Proxy(clazz, String::class.java, /* Unused */ SerializerFactory(), withInheritance) { + private val maker: (String) -> T = clazz.getConstructor(String::class.java).let { + `constructor` -> { string -> `constructor`.newInstance(string) } + }, + private val unmaker: (T) -> String = { obj -> obj.toString() }) : Proxy(clazz, String::class.java, /* Unused */ SerializerFactoryFactory.get(), withInheritance) { override val additionalSerializers: Iterable> = emptyList() diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializationInput.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializationInput.kt index 5654dfa20d..8764064116 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializationInput.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializationInput.kt @@ -20,7 +20,7 @@ data class ObjectAndEnvelope(val obj: T, val envelope: Envelope) * @param serializerFactory This is the factory for [AMQPSerializer] instances and can be shared across multiple * instances and threads. */ -class DeserializationInput(internal val serializerFactory: SerializerFactory = SerializerFactory()) { +class DeserializationInput(internal val serializerFactory: SerializerFactory = SerializerFactoryFactory.get()) { // TODO: we're not supporting object refs yet private val objectHistory: MutableList = ArrayList() diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutput.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutput.kt index 90011f149c..7e47932f06 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutput.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutput.kt @@ -14,7 +14,7 @@ import kotlin.collections.LinkedHashSet * @param serializerFactory This is the factory for [AMQPSerializer] instances and can be shared across multiple * instances and threads. */ -open class SerializationOutput(internal val serializerFactory: SerializerFactory = SerializerFactory()) { +open class SerializationOutput(internal val serializerFactory: SerializerFactory = SerializerFactoryFactory.get()) { // TODO: we're not supporting object refs yet private val objectHistory: MutableMap = IdentityHashMap() private val serializerHistory: MutableSet> = LinkedHashSet() diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt index 9b20b08a5c..b88c89d99c 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactory.kt @@ -44,11 +44,13 @@ import javax.annotation.concurrent.ThreadSafe // TODO: need to rethink matching of constructor to properties in relation to implementing interfaces and needing those properties etc. // TODO: need to support super classes as well as interfaces with our current code base... what's involved? If we continue to ban, what is the impact? @ThreadSafe -class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { +class SerializerFactory(val whitelist: ClassWhitelist, cl : ClassLoader) { private val serializersByType = ConcurrentHashMap>() private val serializersByDescriptor = ConcurrentHashMap>() private val customSerializers = CopyOnWriteArrayList>() - private val classCarpenter = ClassCarpenter() + private val classCarpenter = ClassCarpenter(cl) + val classloader : ClassLoader + get() = classCarpenter.classloader /** * Look up, and manufacture if necessary, a serializer for the given type. @@ -176,15 +178,18 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { } } + /** + * Iterate over an AMQP schema, for each type ascertain weather it's on ClassPath of [classloader] amd + * if not use the [ClassCarpenter] to generate a class to use in it's place + */ private fun processSchema(schema: Schema, sentinal: Boolean = false) { val carpenterSchemas = CarpenterSchemas.newInstance() for (typeNotation in schema.types) { try { - processSchemaEntry(typeNotation, classCarpenter.classloader) - } catch (e: ClassNotFoundException) { + } + catch (e: ClassNotFoundException) { if (sentinal || (typeNotation !is CompositeType)) throw e - typeNotation.carpenterSchema( - classLoaders = listOf(classCarpenter.classloader), carpenterSchemas = carpenterSchemas) + typeNotation.carpenterSchema(classloader, carpenterSchemas = carpenterSchemas) } } @@ -195,10 +200,9 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { } } - private fun processSchemaEntry(typeNotation: TypeNotation, - cl: ClassLoader = DeserializedParameterizedType::class.java.classLoader) { + private fun processSchemaEntry(typeNotation: TypeNotation) { when (typeNotation) { - is CompositeType -> processCompositeType(typeNotation, cl) // java.lang.Class (whether a class or interface) + is CompositeType -> processCompositeType(typeNotation) // java.lang.Class (whether a class or interface) is RestrictedType -> processRestrictedType(typeNotation) // Collection / Map, possibly with generics } } @@ -210,7 +214,6 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { } private fun processCompositeType(typeNotation: CompositeType, - cl: ClassLoader = DeserializedParameterizedType::class.java.classLoader) { // TODO: class loader logic, and compare the schema. val type = typeForName(typeNotation.name, cl) get(type.asClass() ?: throw NotSerializableException("Unable to build composite type for $type"), type) @@ -322,11 +325,9 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { else -> throw NotSerializableException("Unable to render type $type to a string.") } - private fun typeForName( - name: String, - cl: ClassLoader = DeserializedParameterizedType::class.java.classLoader): Type { + private fun typeForName(name: String, classloader: ClassLoader): Type { return if (name.endsWith("[]")) { - val elementType = typeForName(name.substring(0, name.lastIndex - 1)) + val elementType = typeForName(name.substring(0, name.lastIndex - 1), classloader) if (elementType is ParameterizedType || elementType is GenericArrayType) { DeserializedGenericArrayType(elementType) } else if (elementType is Class<*>) { @@ -349,7 +350,7 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) { else -> throw NotSerializableException("Not able to deserialize array type: $name") } } else { - DeserializedParameterizedType.make(name, cl) + DeserializedParameterizedType.make(name, classloader) } } } diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactoryFactory.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactoryFactory.kt new file mode 100644 index 0000000000..81a2643918 --- /dev/null +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializerFactoryFactory.kt @@ -0,0 +1,22 @@ +package net.corda.nodeapi.internal.serialization.amqp + +import net.corda.core.serialization.SerializationContext +import net.corda.core.serialization.ClassWhitelist +import net.corda.nodeapi.internal.serialization.AllWhitelist + +/** + * Factory singleton that maps unique Serializer Factories from a pair of WhitleList and ClassLoader + */ +object SerializerFactoryFactory { + val factories : MutableMap, SerializerFactory> = mutableMapOf() + + fun get(context: SerializationContext) : SerializerFactory = + factories.computeIfAbsent(Pair(context.whitelist, context.deserializationClassLoader)) { + SerializerFactory(context.whitelist, context.deserializationClassLoader) + } + + fun get() : SerializerFactory = + factories.computeIfAbsent(Pair(AllWhitelist, ClassLoader.getSystemClassLoader())) { + SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + } +} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/AMQPSchemaExtensions.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/AMQPSchemaExtensions.kt index dbe8bb254d..eb1f21f54a 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/AMQPSchemaExtensions.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/AMQPSchemaExtensions.kt @@ -4,13 +4,11 @@ import net.corda.nodeapi.internal.serialization.amqp.CompositeType import net.corda.nodeapi.internal.serialization.amqp.Field as AMQPField import net.corda.nodeapi.internal.serialization.amqp.Schema as AMQPSchema -fun AMQPSchema.carpenterSchema( - loaders: List = listOf(ClassLoader.getSystemClassLoader())) - : CarpenterSchemas { +fun AMQPSchema.carpenterSchema(classloader: ClassLoader) : CarpenterSchemas { val rtn = CarpenterSchemas.newInstance() types.filterIsInstance().forEach { - it.carpenterSchema(classLoaders = loaders, carpenterSchemas = rtn) + it.carpenterSchema(classloader, carpenterSchemas = rtn) } return rtn @@ -19,10 +17,9 @@ fun AMQPSchema.carpenterSchema( /** * if we can load the class then we MUST know about all of it's composite elements */ -private fun CompositeType.validatePropertyTypes( - classLoaders: List = listOf(ClassLoader.getSystemClassLoader())) { +private fun CompositeType.validatePropertyTypes(classloader: ClassLoader) { fields.forEach { - if (!it.validateType(classLoaders)) throw UncarpentableException(name, it.name, it.type) + if (!it.validateType(classloader)) throw UncarpentableException(name, it.name, it.type) } } @@ -34,24 +31,21 @@ fun AMQPField.typeAsString() = if (type == "*") requires[0] else type * b) add the class to the dependency tree in [carpenterSchemas] if it cannot be instantiated * at this time * - * @param classLoaders list of classLoaders, defaulting toe the system class loader, that might - * be used to load objects + * @param classloader the class loader provided dby the [SerializationContext] * @param carpenterSchemas structure that holds the dependency tree and list of classes that * need constructing * @param force by default a schema is not added to [carpenterSchemas] if it already exists * on the class path. For testing purposes schema generation can be forced */ -fun CompositeType.carpenterSchema( - classLoaders: List = listOf(ClassLoader.getSystemClassLoader()), - carpenterSchemas: CarpenterSchemas, - force: Boolean = false) { - if (classLoaders.exists(name)) { - validatePropertyTypes(classLoaders) +fun CompositeType.carpenterSchema(classloader: ClassLoader, + carpenterSchemas: CarpenterSchemas, + force: Boolean = false) { + if (classloader.exists(name)) { + validatePropertyTypes(classloader) if (!force) return } val providesList = mutableListOf>() - var isInterface = false var isCreatable = true @@ -62,7 +56,7 @@ fun CompositeType.carpenterSchema( } try { - providesList.add(classLoaders.loadIfExists(it)) + providesList.add(classloader.loadClass(it)) } catch (e: ClassNotFoundException) { carpenterSchemas.addDepPair(this, name, it) isCreatable = false @@ -73,7 +67,7 @@ fun CompositeType.carpenterSchema( fields.forEach { try { - m[it.name] = FieldFactory.newInstance(it.mandatory, it.name, it.getTypeAsClass(classLoaders)) + m[it.name] = FieldFactory.newInstance(it.mandatory, it.name, it.getTypeAsClass(classloader)) } catch (e: ClassNotFoundException) { carpenterSchemas.addDepPair(this, name, it.typeAsString()) isCreatable = false @@ -110,33 +104,18 @@ val typeStrToType: Map, Class> = mapOf( Pair("byte", false) to Byte::class.javaObjectType ) -fun AMQPField.getTypeAsClass( - classLoaders: List = listOf(ClassLoader.getSystemClassLoader()) -) = typeStrToType[Pair(type, mandatory)] ?: when (type) { +fun AMQPField.getTypeAsClass(classloader: ClassLoader) = typeStrToType[Pair(type, mandatory)] ?: when (type) { "string" -> String::class.java - "*" -> classLoaders.loadIfExists(requires[0]) - else -> classLoaders.loadIfExists(type) + "*" -> classloader.loadClass(requires[0]) + else -> classloader.loadClass(type) } -fun AMQPField.validateType( - classLoaders: List = listOf(ClassLoader.getSystemClassLoader()) -) = when (type) { +fun AMQPField.validateType(classloader: ClassLoader) = when (type) { "byte", "int", "string", "short", "long", "char", "boolean", "double", "float" -> true - "*" -> classLoaders.exists(requires[0]) - else -> classLoaders.exists(type) + "*" -> classloader.exists(requires[0]) + else -> classloader.exists(type) } -private fun List.exists(clazz: String) = this.find { - try { it.loadClass(clazz); true } catch (e: ClassNotFoundException) { false } -} != null +private fun ClassLoader.exists(clazz: String) = run { + try { this.loadClass(clazz); true } catch (e: ClassNotFoundException) { false } } -private fun List.loadIfExists(clazz: String): Class<*> { - this.forEach { - try { - return it.loadClass(clazz) - } catch (e: ClassNotFoundException) { - return@forEach - } - } - throw ClassNotFoundException(clazz) -} diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenter.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenter.kt index 21641a0ae1..a62be2da34 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenter.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenter.kt @@ -18,7 +18,8 @@ interface SimpleFieldAccess { operator fun get(name: String): Any? } -class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoader) { +class CarpenterClassLoader (parentClassLoader: ClassLoader = Thread.currentThread().contextClassLoader) : + ClassLoader(parentClassLoader) { fun load(name: String, bytes: ByteArray) = defineClass(name, bytes, 0, bytes.size) } @@ -66,14 +67,14 @@ class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoad * * Equals/hashCode methods are not yet supported. */ -class ClassCarpenter { +class ClassCarpenter(cl: ClassLoader = Thread.currentThread().contextClassLoader) { // TODO: Generics. // TODO: Sandbox the generated code when a security manager is in use. // TODO: Generate equals/hashCode. // TODO: Support annotations. // TODO: isFoo getter patterns for booleans (this is what Kotlin generates) - val classloader = CarpenterClassLoader() + val classloader = CarpenterClassLoader(cl) private val _loaded = HashMap>() private val String.jvm: String get() = replace(".", "/") diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MetaCarpenter.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MetaCarpenter.kt index 77e866fb32..fb0d1f7001 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MetaCarpenter.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MetaCarpenter.kt @@ -73,9 +73,7 @@ abstract class MetaCarpenterBase (val schemas : CarpenterSchemas, val cc : Class // we're out of blockers so we can now create the type if (schemas.dependencies[dependent]?.second?.isEmpty() ?: false) { (schemas.dependencies.remove (dependent)?.first as CompositeType).carpenterSchema ( - classLoaders = listOf ( - ClassLoader.getSystemClassLoader(), - cc.classloader), + classloader = cc.classloader, carpenterSchemas = schemas) } } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPTestUtils.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPTestUtils.kt index 19b93b6542..c22a70f4d9 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPTestUtils.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/AMQPTestUtils.kt @@ -4,7 +4,7 @@ import org.apache.qpid.proton.codec.Data class TestSerializationOutput( private val verbose: Boolean, - serializerFactory: SerializerFactory = SerializerFactory()) : SerializationOutput(serializerFactory) { + serializerFactory: SerializerFactory = SerializerFactoryFactory.get()) : SerializationOutput(serializerFactory) { override fun writeSchema(schema: Schema, data: Data) { if (verbose) println(schema) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeAndReturnEnvelopeTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeAndReturnEnvelopeTests.kt index b91fa3fe9e..39ed38bea4 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeAndReturnEnvelopeTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeAndReturnEnvelopeTests.kt @@ -18,7 +18,7 @@ class DeserializeAndReturnEnvelopeTests { val a = A(10, "20") - val factory = SerializerFactory() + val factory = SerializerFactoryFactory.get() fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz) val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a)) @@ -34,7 +34,7 @@ class DeserializeAndReturnEnvelopeTests { val b = B(A(10, "20"), 30.0F) - val factory = SerializerFactory() + val factory = SerializerFactoryFactory.get() fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz) val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b)) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt index 76933fb370..01fb68a22f 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentrySimpleTypesTest.kt @@ -8,7 +8,7 @@ import net.corda.nodeapi.internal.serialization.carpenter.* // those classes don't exist within the system's Class Loader the deserialiser will be forced to carpent // versions of them up using its own internal class carpenter (each carpenter houses it's own loader). This // replicates the situation where a receiver doesn't have some or all elements of a schema present on it's classpath -class DeserializeNeedingCarpentrySimpleTypesTest { +class DeserializeNeedingCarpentrySimpleTypesTest : AmqpCarpenterBase() { companion object { /** * If you want to see the schema encoded into the envelope after serialisation change this to true @@ -21,7 +21,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleInt() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "int" to NonNullableField(Integer::class.javaPrimitiveType!!) ))) @@ -41,7 +41,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleIntNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "int" to NullableField(Integer::class.java) ))) @@ -57,7 +57,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleIntNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "int" to NullableField(Integer::class.java) ))) @@ -73,7 +73,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleChar() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "char" to NonNullableField(Character::class.javaPrimitiveType!!) ))) @@ -86,7 +86,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleCharNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "char" to NullableField(Character::class.javaObjectType) ))) @@ -99,7 +99,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleCharNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "char" to NullableField(java.lang.Character::class.java) ))) @@ -112,7 +112,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleLong() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "long" to NonNullableField(Long::class.javaPrimitiveType!!) ))) @@ -126,7 +126,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleLongNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "long" to NullableField(Long::class.javaObjectType) ))) @@ -140,7 +140,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleLongNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "long" to NullableField(Long::class.javaObjectType) ))) @@ -153,7 +153,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleBoolean() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "boolean" to NonNullableField(Boolean::class.javaPrimitiveType!!) ))) @@ -166,7 +166,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleBooleanNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "boolean" to NullableField(Boolean::class.javaObjectType) ))) @@ -179,7 +179,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleBooleanNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "boolean" to NullableField(Boolean::class.javaObjectType) ))) @@ -192,7 +192,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleDouble() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "double" to NonNullableField(Double::class.javaPrimitiveType!!) ))) @@ -205,7 +205,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleDoubleNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "double" to NullableField(Double::class.javaObjectType) ))) @@ -218,7 +218,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleDoubleNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "double" to NullableField(Double::class.javaObjectType) ))) @@ -231,7 +231,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleShort() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "short" to NonNullableField(Short::class.javaPrimitiveType!!) ))) @@ -244,7 +244,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleShortNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "short" to NullableField(Short::class.javaObjectType) ))) @@ -257,7 +257,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleShortNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "short" to NullableField(Short::class.javaObjectType) ))) @@ -270,7 +270,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleFloat() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "float" to NonNullableField(Float::class.javaPrimitiveType!!) ))) @@ -283,7 +283,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleFloatNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "float" to NullableField(Float::class.javaObjectType) ))) @@ -296,7 +296,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleFloatNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "float" to NullableField(Float::class.javaObjectType) ))) @@ -309,7 +309,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleByte() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "byte" to NonNullableField(Byte::class.javaPrimitiveType!!) ))) @@ -324,7 +324,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleByteNullable() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "byte" to NullableField(Byte::class.javaObjectType) ))) @@ -339,7 +339,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun singleByteNullableNull() { - val clazz = ClassCarpenter().build(ClassSchema("single", mapOf( + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf( "byte" to NullableField(Byte::class.javaObjectType) ))) @@ -353,11 +353,10 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun simpleTypeKnownInterface() { val clazz = ClassCarpenter().build (ClassSchema( - "oneType", mapOf("name" to NonNullableField(String::class.java)), + testName(), mapOf("name" to NonNullableField(String::class.java)), interfaces = listOf (I::class.java))) val testVal = "Some Person" val classInstance = clazz.constructors[0].newInstance(testVal) - val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(classInstance) val deserializedObj = DeserializationInput(sf2).deserialize(serialisedBytes) @@ -368,7 +367,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { @Test fun manyTypes() { - val manyClass = ClassCarpenter().build (ClassSchema("many", mapOf( + val manyClass = ClassCarpenter().build (ClassSchema(testName(), mapOf( "intA" to NonNullableField (Int::class.java), "intB" to NullableField (Integer::class.java), "intC" to NullableField (Integer::class.java), @@ -397,7 +396,7 @@ class DeserializeNeedingCarpentrySimpleTypesTest { "byteB" to NullableField (Byte::class.javaObjectType), "byteC" to NullableField (Byte::class.javaObjectType)))) - val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize( + val serialisedBytes = TestSerializationOutput(VERBOSE, factory).serialize( manyClass.constructors.first().newInstance( 1, 2, null, "a", "b", null, diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentryTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentryTests.kt index d0cae9e3b6..d8feeb8473 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentryTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeNeedingCarpentryTests.kt @@ -3,22 +3,21 @@ package net.corda.nodeapi.internal.serialization.amqp import org.junit.Test import kotlin.test.* import net.corda.nodeapi.internal.serialization.carpenter.* +import net.corda.nodeapi.internal.serialization.AllWhitelist interface I { fun getName() : String } -/** - * These tests work by having the class carpenter build the classes we serialise and then deserialise them - * within the context of a second serialiser factory. The second factory is required as the first, having - * been used to serialise the class, will have cached a copy of the class and will thus bypass the need - * to pull it out of the class loader. - * - * However, those classes don't exist within the system's Class Loader and thus the deserialiser will be forced - * to carpent versions of them up using its own internal class carpenter (each carpenter houses it's own loader). This - * replicates the situation where a receiver doesn't have some or all elements of a schema present on it's classpath - */ -class DeserializeNeedingCarpentryTests { +// These tests work by having the class carpenter build the classes we serialise and then deserialise them +// within the context of a second serialiser factory. The second factory is required as the first, having +// been used to serialise the class, will have cached a copy of the class and will thus bypass the need +// to pull it out of the class loader. +// +// However, those classes don't exist within the system's Class Loader and thus the deserialiser will be forced +// to carpent versions of them up using its own internal class carpenter (each carpenter houses it's own loader). This +// replicates the situation where a receiver doesn't have some or all elements of a schema present on it's classpath +class DeserializeNeedingCarpentryTests : AmqpCarpenterBase() { companion object { /** * If you want to see the schema encoded into the envelope after serialisation change this to true @@ -32,7 +31,7 @@ class DeserializeNeedingCarpentryTests { @Test fun verySimpleType() { val testVal = 10 - val clazz = ClassCarpenter().build(ClassSchema("oneType", mapOf("a" to NonNullableField(Int::class.java)))) + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf("a" to NonNullableField(Int::class.java)))) val classInstance = clazz.constructors[0].newInstance(testVal) val serialisedBytes = TestSerializationOutput(VERBOSE, sf1).serialize(classInstance) @@ -66,16 +65,20 @@ class DeserializeNeedingCarpentryTests { val testValA = 10 val testValB = 20 val testValC = 20 - val clazz = ClassCarpenter().build(ClassSchema("oneType", mapOf("a" to NonNullableField(Int::class.java)))) + val clazz = ClassCarpenter().build(ClassSchema("${testName()}_clazz", + mapOf("a" to NonNullableField(Int::class.java)))) + val concreteA = clazz.constructors[0].newInstance(testValA) val concreteB = clazz.constructors[0].newInstance(testValB) val concreteC = clazz.constructors[0].newInstance(testValC) - val deserialisedA = DeserializationInput(sf2).deserialize(TestSerializationOutput(VERBOSE, sf1).serialize(concreteA)) + val deserialisedA = DeserializationInput(sf2).deserialize( + TestSerializationOutput(VERBOSE, sf1).serialize(concreteA)) assertEquals (testValA, deserialisedA::class.java.getMethod("getA").invoke(deserialisedA)) - val deserialisedB = DeserializationInput(sf2).deserialize(TestSerializationOutput(VERBOSE, sf1).serialize(concreteB)) + val deserialisedB = DeserializationInput(sf2).deserialize( + TestSerializationOutput(VERBOSE, sf1).serialize(concreteB)) assertEquals (testValB, deserialisedA::class.java.getMethod("getA").invoke(deserialisedB)) assertEquals (deserialisedA::class.java, deserialisedB::class.java) @@ -84,8 +87,10 @@ class DeserializeNeedingCarpentryTests { // won't already exist and it will be carpented a second time showing that when A and B are the // same underlying class that we didn't create a second instance of the class with the // second deserialisation - val lsf = SerializerFactory() - val deserialisedC = DeserializationInput(lsf).deserialize(TestSerializationOutput(VERBOSE, lsf).serialize(concreteC)) + val lfactory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + val deserialisedC = DeserializationInput(lfactory).deserialize( + TestSerializationOutput(VERBOSE, lfactory).serialize(concreteC)) + assertEquals (testValC, deserialisedC::class.java.getMethod("getA").invoke(deserialisedC)) assertNotEquals (deserialisedA::class.java, deserialisedC::class.java) assertNotEquals (deserialisedB::class.java, deserialisedC::class.java) @@ -94,7 +99,7 @@ class DeserializeNeedingCarpentryTests { @Test fun simpleTypeKnownInterface() { val clazz = ClassCarpenter().build (ClassSchema( - "oneType", mapOf("name" to NonNullableField(String::class.java)), + testName(), mapOf("name" to NonNullableField(String::class.java)), interfaces = listOf (I::class.java))) val testVal = "Some Person" val classInstance = clazz.constructors[0].newInstance(testVal) @@ -108,7 +113,7 @@ class DeserializeNeedingCarpentryTests { @Test fun arrayOfTypes() { - val clazz = ClassCarpenter().build(ClassSchema("oneType", mapOf("a" to NonNullableField(Int::class.java)))) + val clazz = ClassCarpenter().build(ClassSchema(testName(), mapOf("a" to NonNullableField(Int::class.java)))) data class Outer (val a : Array) @@ -142,8 +147,8 @@ class DeserializeNeedingCarpentryTests { fun reusedClasses() { val cc = ClassCarpenter() - val innerType = cc.build(ClassSchema("inner", mapOf("a" to NonNullableField(Int::class.java)))) - val outerType = cc.build(ClassSchema("outer", mapOf("a" to NonNullableField(innerType)))) + val innerType = cc.build(ClassSchema("${testName()}.inner", mapOf("a" to NonNullableField(Int::class.java)))) + val outerType = cc.build(ClassSchema("${testName()}.outer", mapOf("a" to NonNullableField(innerType)))) val inner = innerType.constructors[0].newInstance(1) val outer = outerType.constructors[0].newInstance(innerType.constructors[0].newInstance(2)) @@ -160,7 +165,7 @@ class DeserializeNeedingCarpentryTests { @Test fun nestedTypes() { val cc = ClassCarpenter() - val nestedClass = cc.build (ClassSchema("nestedType", + val nestedClass = cc.build (ClassSchema(testName(), mapOf("name" to NonNullableField(String::class.java)))) val outerClass = cc.build (ClassSchema("outerType", @@ -169,23 +174,6 @@ class DeserializeNeedingCarpentryTests { val classInstance = outerClass.constructors.first().newInstance(nestedClass.constructors.first().newInstance("name")) val serialisedBytes = TestSerializationOutput(VERBOSE, sf1).serialize(classInstance) val deserializedObj = DeserializationInput(sf2).deserialize(serialisedBytes) - - val inner = deserializedObj::class.java.getMethod("getInner").invoke(deserializedObj) - assertEquals("name", inner::class.java.getMethod("getName").invoke(inner)) - } - - @Test - fun repeatedNestedTypes() { - val cc = ClassCarpenter() - val nestedClass = cc.build (ClassSchema("nestedType", - mapOf("name" to NonNullableField(String::class.java)))) - - data class outer(val a: Any, val b: Any) - - val classInstance = outer ( - nestedClass.constructors.first().newInstance("foo"), - nestedClass.constructors.first().newInstance("bar")) - val serialisedBytes = TestSerializationOutput(VERBOSE, sf1).serialize(classInstance) val deserializedObj = DeserializationInput(sf2).deserialize(serialisedBytes) @@ -195,7 +183,7 @@ class DeserializeNeedingCarpentryTests { @Test fun listOfType() { - val unknownClass = ClassCarpenter().build (ClassSchema("unknownClass", mapOf( + val unknownClass = ClassCarpenter().build (ClassSchema(testName(), mapOf( "v1" to NonNullableField(Int::class.java), "v2" to NonNullableField(Int::class.java)))) @@ -223,7 +211,7 @@ class DeserializeNeedingCarpentryTests { "gen.Interface", mapOf("age" to NonNullableField (Int::class.java)))) - val concreteClass = cc.build (ClassSchema ("gen.Class", mapOf( + val concreteClass = cc.build (ClassSchema (testName(), mapOf( "age" to NonNullableField (Int::class.java), "name" to NonNullableField(String::class.java)), interfaces = listOf (I::class.java, interfaceClass))) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/JavaSerializationOutputTests.java b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/JavaSerializationOutputTests.java index afb558ebdb..ff20bffe97 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/JavaSerializationOutputTests.java +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/JavaSerializationOutputTests.java @@ -1,5 +1,6 @@ package net.corda.nodeapi.internal.serialization.amqp; +import net.corda.nodeapi.internal.serialization.AllWhitelist; import net.corda.core.serialization.SerializedBytes; import org.apache.qpid.proton.codec.DecoderImpl; import org.apache.qpid.proton.codec.EncoderImpl; @@ -167,7 +168,7 @@ public class JavaSerializationOutputTests { } private Object serdes(Object obj) throws NotSerializableException { - SerializerFactory factory = new SerializerFactory(); + SerializerFactory factory = new SerializerFactory(AllWhitelist.INSTANCE, ClassLoader.getSystemClassLoader()); SerializationOutput ser = new SerializationOutput(factory); SerializedBytes bytes = ser.serialize(obj); diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt index 53bdaaafe1..3f4e534004 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/SerializationOutputTests.kt @@ -14,7 +14,6 @@ import net.corda.nodeapi.RPCException import net.corda.nodeapi.internal.serialization.AbstractAMQPSerializationScheme import net.corda.nodeapi.internal.serialization.EmptyWhitelist import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.isPrimitive -import net.corda.nodeapi.internal.serialization.amqp.custom.* import net.corda.testing.MEGA_CORP import net.corda.testing.MEGA_CORP_PUBKEY import org.apache.qpid.proton.amqp.* @@ -136,8 +135,9 @@ class SerializationOutputTests { data class PolymorphicProperty(val foo: FooInterface?) private fun serdes(obj: Any, - factory: SerializerFactory = SerializerFactory(), - freshDeserializationFactory: SerializerFactory = SerializerFactory(), + factory: SerializerFactory = SerializerFactoryFactory.get(), + freshDeserializationFactory: SerializerFactory = SerializerFactory( + AllWhitelist, ClassLoader.getSystemClassLoader()), expectedEqual: Boolean = true, expectDeserializedEqual: Boolean = true): Any { val ser = SerializationOutput(factory) @@ -285,13 +285,13 @@ class SerializationOutputTests { @Test(expected = NotSerializableException::class) fun `test whitelist`() { val obj = Woo2(4) - serdes(obj, SerializerFactory(EmptyWhitelist)) + serdes(obj, SerializerFactory(EmptyWhitelist, ClassLoader.getSystemClassLoader())) } @Test fun `test annotation whitelisting`() { val obj = AnnotatedWoo(5) - serdes(obj, SerializerFactory(EmptyWhitelist)) + serdes(obj, SerializerFactory(EmptyWhitelist, ClassLoader.getSystemClassLoader())) } @Test(expected = NotSerializableException::class) @@ -387,10 +387,10 @@ class SerializationOutputTests { @Test fun `test custom serializers on public key`() { - val factory = SerializerFactory() - factory.register(PublicKeySerializer) - val factory2 = SerializerFactory() - factory2.register(PublicKeySerializer) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.PublicKeySerializer) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.PublicKeySerializer) val obj = MEGA_CORP_PUBKEY serdes(obj, factory, factory2) } @@ -398,16 +398,16 @@ class SerializationOutputTests { @Test fun `test annotation is inherited`() { val obj = InheritAnnotation("blah") - serdes(obj, SerializerFactory(EmptyWhitelist)) + serdes(obj, SerializerFactory(EmptyWhitelist, ClassLoader.getSystemClassLoader())) } @Test fun `test throwables serialize`() { - val factory = SerializerFactory() - factory.register(ThrowableSerializer(factory)) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory)) - val factory2 = SerializerFactory() - factory2.register(ThrowableSerializer(factory2)) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2)) val t = IllegalAccessException("message").fillInStackTrace() val desThrowable = serdes(t, factory, factory2, false) as Throwable @@ -416,11 +416,11 @@ class SerializationOutputTests { @Test fun `test complex throwables serialize`() { - val factory = SerializerFactory() - factory.register(ThrowableSerializer(factory)) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory)) - val factory2 = SerializerFactory() - factory2.register(ThrowableSerializer(factory2)) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2)) try { try { @@ -447,11 +447,11 @@ class SerializationOutputTests { @Test fun `test suppressed throwables serialize`() { - val factory = SerializerFactory() - factory.register(ThrowableSerializer(factory)) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory)) - val factory2 = SerializerFactory() - factory2.register(ThrowableSerializer(factory2)) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2)) try { try { @@ -469,11 +469,11 @@ class SerializationOutputTests { @Test fun `test flow corda exception subclasses serialize`() { - val factory = SerializerFactory() - factory.register(ThrowableSerializer(factory)) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory)) - val factory2 = SerializerFactory() - factory2.register(ThrowableSerializer(factory2)) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2)) val obj = FlowException("message").fillInStackTrace() serdes(obj, factory, factory2) @@ -481,11 +481,11 @@ class SerializationOutputTests { @Test fun `test RPC corda exception subclasses serialize`() { - val factory = SerializerFactory() - factory.register(ThrowableSerializer(factory)) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory)) - val factory2 = SerializerFactory() - factory2.register(ThrowableSerializer(factory2)) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.ThrowableSerializer(factory2)) val obj = RPCException("message").fillInStackTrace() serdes(obj, factory, factory2) @@ -525,7 +525,7 @@ class SerializationOutputTests { @Test fun `test transaction state`() { - val state = TransactionState(FooState(), MEGA_CORP) + val state = TransactionState(FooState(), MEGA_CORP) val factory = SerializerFactory() AbstractAMQPSerializationScheme.registerCustomSerializers(factory) @@ -542,11 +542,11 @@ class SerializationOutputTests { @Test fun `test currencies serialize`() { - val factory = SerializerFactory() - factory.register(CurrencySerializer) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.CurrencySerializer) - val factory2 = SerializerFactory() - factory2.register(CurrencySerializer) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.CurrencySerializer) val obj = Currency.getInstance("USD") serdes(obj, factory, factory2) @@ -554,11 +554,11 @@ class SerializationOutputTests { @Test fun `test big decimals serialize`() { - val factory = SerializerFactory() - factory.register(BigDecimalSerializer) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.BigDecimalSerializer) - val factory2 = SerializerFactory() - factory2.register(BigDecimalSerializer) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.BigDecimalSerializer) val obj = BigDecimal("100000000000000000000000000000.00") serdes(obj, factory, factory2) @@ -566,11 +566,11 @@ class SerializationOutputTests { @Test fun `test instants serialize`() { - val factory = SerializerFactory() - factory.register(InstantSerializer(factory)) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(factory)) - val factory2 = SerializerFactory() - factory2.register(InstantSerializer(factory2)) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(factory2)) val obj = Instant.now() serdes(obj, factory, factory2) @@ -578,11 +578,11 @@ class SerializationOutputTests { @Test fun `test StateRef serialize`() { - val factory = SerializerFactory() - factory.register(InstantSerializer(factory)) + val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(factory)) - val factory2 = SerializerFactory() - factory2.register(InstantSerializer(factory2)) + val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) + factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.InstantSerializer(factory2)) val obj = StateRef(SecureHash.randomSHA256(), 0) serdes(obj, factory, factory2) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenterTestUtils.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenterTestUtils.kt index 3aae840918..2dd62bff58 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenterTestUtils.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/ClassCarpenterTestUtils.kt @@ -4,8 +4,8 @@ import net.corda.nodeapi.internal.serialization.amqp.Field import net.corda.nodeapi.internal.serialization.amqp.Schema import net.corda.nodeapi.internal.serialization.amqp.TypeNotation import net.corda.nodeapi.internal.serialization.amqp.CompositeType -import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory import net.corda.nodeapi.internal.serialization.amqp.SerializationOutput +import net.corda.nodeapi.internal.serialization.amqp.SerializerFactoryFactory fun mangleName(name: String) = "${name}__carpenter" @@ -37,7 +37,7 @@ fun Schema.mangleNames(names: List): Schema { } open class AmqpCarpenterBase { - var factory = SerializerFactory() + var factory = SerializerFactoryFactory.get() fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz) fun testName(): String = Thread.currentThread().stackTrace[2].methodName diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/CompositeMemberCompositeSchemaToClassCarpenterTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/CompositeMemberCompositeSchemaToClassCarpenterTests.kt index 5ec40e0f4e..a61bee62f7 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/CompositeMemberCompositeSchemaToClassCarpenterTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/CompositeMemberCompositeSchemaToClassCarpenterTests.kt @@ -63,7 +63,7 @@ class CompositeMembers : AmqpCarpenterBase() { assertEquals("b", amqpSchemaB.fields[1].name) assertEquals("int", amqpSchemaB.fields[1].type) - val metaSchema = obj.envelope.schema.carpenterSchema() + val metaSchema = obj.envelope.schema.carpenterSchema(ClassLoader.getSystemClassLoader()) // if we know all the classes there is nothing to really achieve here assert(metaSchema.carpenterSchemas.isEmpty()) @@ -92,7 +92,7 @@ class CompositeMembers : AmqpCarpenterBase() { assert(obj.obj is B) - amqpSchema.carpenterSchema() + amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) } @Test @@ -112,7 +112,7 @@ class CompositeMembers : AmqpCarpenterBase() { assert(obj.obj is B) val amqpSchema = obj.envelope.schema.mangleNames(listOf(classTestName("B"))) - val carpenterSchema = amqpSchema.carpenterSchema() + val carpenterSchema = amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) assertEquals(1, carpenterSchema.size) @@ -140,7 +140,7 @@ class CompositeMembers : AmqpCarpenterBase() { assert(obj.obj is B) val amqpSchema = obj.envelope.schema.mangleNames(listOf(classTestName("A"), classTestName("B"))) - val carpenterSchema = amqpSchema.carpenterSchema() + val carpenterSchema = amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) // just verify we're in the expected initial state, A is carpentable, B is not because // it depends on A and the dependency chains are in place @@ -200,7 +200,7 @@ class CompositeMembers : AmqpCarpenterBase() { val amqpSchema = obj.envelope.schema.mangleNames(listOf(classTestName("A"), classTestName("B"))) - amqpSchema.carpenterSchema() + amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) } @Test(expected = UncarpentableException::class) @@ -226,7 +226,7 @@ class CompositeMembers : AmqpCarpenterBase() { val amqpSchema = obj.envelope.schema.mangleNames(listOf(classTestName("A"), classTestName("B"))) - amqpSchema.carpenterSchema() + amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) } @Suppress("UNUSED") @@ -251,7 +251,7 @@ class CompositeMembers : AmqpCarpenterBase() { assert(obj.obj is C) val carpenterSchema = obj.envelope.schema.mangleNames(listOf(classTestName("A"), classTestName("B"))) - TestMetaCarpenter(carpenterSchema.carpenterSchema()) + TestMetaCarpenter(carpenterSchema.carpenterSchema(ClassLoader.getSystemClassLoader())) } /* diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/InheritanceSchemaToClassCarpenterTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/InheritanceSchemaToClassCarpenterTests.kt index 8176823aa3..81cf727c58 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/InheritanceSchemaToClassCarpenterTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/InheritanceSchemaToClassCarpenterTests.kt @@ -45,14 +45,14 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertTrue(obj.obj is A) val serSchema = obj.envelope.schema assertEquals(2, serSchema.types.size) - val l1 = serSchema.carpenterSchema() + val l1 = serSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) // since we're using an envelope generated by seilaising classes defined locally // it's extremely unlikely we'd need to carpent any classes assertEquals(0, l1.size) val mangleSchema = serSchema.mangleNames(listOf(classTestName("A"))) - val l2 = mangleSchema.carpenterSchema() + val l2 = mangleSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) assertEquals(1, l2.size) val aSchema = l2.carpenterSchemas.find { it.name == mangleName(classTestName("A")) } @@ -88,13 +88,13 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals(2, serSchema.types.size) - val l1 = serSchema.carpenterSchema() + val l1 = serSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) assertEquals(0, l1.size) val mangleSchema = serSchema.mangleNames(listOf(classTestName("A"))) val aName = mangleName(classTestName("A")) - val l2 = mangleSchema.carpenterSchema() + val l2 = mangleSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) assertEquals(1, l2.size) @@ -132,7 +132,7 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals(3, serSchema.types.size) - val l1 = serSchema.carpenterSchema() + val l1 = serSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) // since we're using an envelope generated by serialising classes defined locally // it's extremely unlikely we'd need to carpent any classes @@ -141,7 +141,7 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { // pretend we don't know the class we've been sent, i.e. it's unknown to the class loader, and thus // needs some carpentry val mangleSchema = serSchema.mangleNames(listOf(classTestName("A"))) - val l2 = mangleSchema.carpenterSchema() + val l2 = mangleSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) val aName = mangleName(classTestName("A")) assertEquals(1, l2.size) @@ -180,14 +180,14 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals(3, serSchema.types.size) - val l1 = serSchema.carpenterSchema() + val l1 = serSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) // since we're using an envelope generated by serialising classes defined locally // it's extremely unlikely we'd need to carpent any classes assertEquals(0, l1.size) val mangleSchema = serSchema.mangleNames(listOf(classTestName("A"))) - val l2 = mangleSchema.carpenterSchema() + val l2 = mangleSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) val aName = mangleName(classTestName("A")) assertEquals(1, l2.size) @@ -235,7 +235,7 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals(4, serSchema.types.size) val mangleSchema = serSchema.mangleNames(listOf(classTestName("A"), classTestName("B"))) - val cSchema = mangleSchema.carpenterSchema() + val cSchema = mangleSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) val aName = mangleName(classTestName("A")) val bName = mangleName(classTestName("B")) @@ -292,7 +292,7 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { // ignore the return as we expect this to throw serSchema.mangleNames(listOf( - classTestName("A"), "${this.javaClass.`package`.name}.I")).carpenterSchema() + classTestName("A"), "${this.javaClass.`package`.name}.I")).carpenterSchema(ClassLoader.getSystemClassLoader()) } @Test @@ -315,7 +315,7 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { val amqpSchema = serSchema.mangleNames(listOf(classTestName("A"), "${this.javaClass.`package`.name}.I")) val aName = mangleName(classTestName("A")) val iName = mangleName("${this.javaClass.`package`.name}.I") - val carpenterSchema = amqpSchema.carpenterSchema() + val carpenterSchema = amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) // whilst there are two unknown classes within the envelope A depends on I so we can't construct a // schema for A until we have for I @@ -362,7 +362,7 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { val aName = mangleName(classTestName("A")) val iName = mangleName("${this.javaClass.`package`.name}.I") val iiName = mangleName("${this.javaClass.`package`.name}.II") - val carpenterSchema = amqpSchema.carpenterSchema() + val carpenterSchema = amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) // there is nothing preventing us from carpenting up the two interfaces so // our initial list should contain both interface with A being dependent on both @@ -414,7 +414,7 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() { val aName = mangleName(classTestName("A")) val iName = mangleName("${this.javaClass.`package`.name}.I") val iiiName = mangleName("${this.javaClass.`package`.name}.III") - val carpenterSchema = amqpSchema.carpenterSchema() + val carpenterSchema = amqpSchema.carpenterSchema(ClassLoader.getSystemClassLoader()) // Since A depends on III and III extends I we will have to construct them // in that reverse order (I -> III -> A) diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MultiMemberCompositeSchemaToClassCarpenterTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MultiMemberCompositeSchemaToClassCarpenterTests.kt index d823e5a8e7..f9ea362882 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MultiMemberCompositeSchemaToClassCarpenterTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/MultiMemberCompositeSchemaToClassCarpenterTests.kt @@ -36,7 +36,10 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals("int", amqpSchema.fields[1].type) val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) assertEquals(1, carpenterSchema.size) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") } @@ -77,7 +80,10 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals("string", amqpSchema.fields[1].type) val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) assertEquals(1, carpenterSchema.size) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") } diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/SingleMemberCompositeSchemaToClassCarpenterTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/SingleMemberCompositeSchemaToClassCarpenterTests.kt index c68e222568..532e174903 100644 --- a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/SingleMemberCompositeSchemaToClassCarpenterTests.kt +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/carpenter/SingleMemberCompositeSchemaToClassCarpenterTests.kt @@ -30,7 +30,10 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals("int", amqpSchema.fields[0].type) val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!! val aBuilder = ClassCarpenter().build(aSchema) @@ -58,7 +61,10 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { val amqpSchema = obj.envelope.schema.types[0] as CompositeType val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!! val aBuilder = ClassCarpenter().build(aSchema) @@ -90,7 +96,10 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals("long", amqpSchema.fields[0].type) val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!! val aBuilder = ClassCarpenter().build(aSchema) @@ -122,7 +131,10 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals("short", amqpSchema.fields[0].type) val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!! val aBuilder = ClassCarpenter().build(aSchema) @@ -154,7 +166,10 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals("double", amqpSchema.fields[0].type) val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!! val aBuilder = ClassCarpenter().build(aSchema) @@ -186,7 +201,10 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() { assertEquals("float", amqpSchema.fields[0].type) val carpenterSchema = CarpenterSchemas.newInstance() - amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true) + amqpSchema.carpenterSchema( + classloader = ClassLoader.getSystemClassLoader(), + carpenterSchemas = carpenterSchema, + force = true) val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!! val aBuilder = ClassCarpenter().build(aSchema)