Merge pull request #1252 from corda/feature/kat/moveAMQPSerialiserTowardCommonInterface

Move AMQP serialiser toward common interface
This commit is contained in:
Katelyn Baker 2017-08-17 09:43:30 +01:00 committed by GitHub
commit 2dc362a409
21 changed files with 261 additions and 253 deletions

View File

@ -41,7 +41,7 @@ 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) }
}

View File

@ -6,12 +6,9 @@ import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output
import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.SerializedBytes
import net.corda.core.utilities.sequence
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
/**
* This [Kryo] custom [Serializer] switches the object graph of anything annotated with `@CordaSerializable`
@ -34,4 +31,4 @@ class KryoAMQPSerializer(val serializationFactory: SerializationFactory, val ser
input.readBytes(allBytes, peekedBytes.size, size - peekedBytes.size)
return serializationFactory.deserialize(allBytes.sequence(), type, serializationContext)
}
}
}

View File

@ -1,5 +1,6 @@
package net.corda.nodeapi.internal.serialization.amqp
import net.corda.core.serialization.SerializationDefaults
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.nameForType
import org.apache.qpid.proton.codec.Data
import java.lang.reflect.Type
@ -68,26 +69,26 @@ abstract class CustomSerializer<T> : AMQPSerializer<T> {
}
/**
* Additional base features for a custom serializer for a particular class, that excludes subclasses.
* Additional base features for a custom serializer for a particular class [withInheritance] is false
* or super class / interfaces [withInheritance] is true
*/
abstract class Is<T>(protected val clazz: Class<T>) : CustomSerializer<T>() {
override fun isSerializerFor(clazz: Class<*>): Boolean = clazz == this.clazz
abstract class CustomSerializerImp<T>(protected val clazz: Class<T>, protected val withInheritance: Boolean) : CustomSerializer<T>() {
override val type: Type get() = clazz
override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${nameForType(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
}
/**
* Additional base features for a custom serializer for a particular class, that excludes subclasses.
*/
abstract class Is<T>(clazz: Class<T>) : CustomSerializerImp<T>(clazz, false)
/**
* Additional base features for a custom serializer for all implementations of a particular interface or super class.
*/
abstract class Implements<T>(protected val clazz: Class<T>) : CustomSerializer<T>() {
override fun isSerializerFor(clazz: Class<*>): Boolean = this.clazz.isAssignableFrom(clazz)
override val type: Type get() = clazz
override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${nameForType(clazz)}"
override fun writeClassInfo(output: SerializationOutput) {}
override val descriptor: Descriptor = Descriptor(typeDescriptor)
}
abstract class Implements<T>(clazz: Class<T>) : CustomSerializerImp<T>(clazz, true)
/**
* Additional base features over and above [Implements] or [Is] custom serializer for when the serialized form should be
@ -96,15 +97,11 @@ abstract class CustomSerializer<T> : AMQPSerializer<T> {
* The proxy class must use only types which are either native AMQP or other types for which there are pre-registered
* custom serializers.
*/
abstract class Proxy<T, P>(protected val clazz: Class<T>,
abstract class Proxy<T, P>(clazz: Class<T>,
protected val proxyClass: Class<P>,
protected val factory: SerializerFactory,
val withInheritance: Boolean = true) : CustomSerializer<T>() {
withInheritance: Boolean = true) : CustomSerializerImp<T>(clazz, withInheritance) {
override fun isSerializerFor(clazz: Class<*>): Boolean = if (withInheritance) this.clazz.isAssignableFrom(clazz) else this.clazz == clazz
override val type: Type get() = clazz
override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${nameForType(clazz)}"
override fun writeClassInfo(output: SerializationOutput) {}
override val descriptor: Descriptor = Descriptor(typeDescriptor)
private val proxySerializer: ObjectSerializer by lazy { ObjectSerializer(proxyClass, factory) }
@ -151,25 +148,27 @@ abstract class CustomSerializer<T> : AMQPSerializer<T> {
* @param unmake A lambda that extracts the string value for an instance, that defaults to the [toString] method.
*/
abstract class ToString<T>(clazz: Class<T>, 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<T, String>(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() })
: CustomSerializerImp<T>(clazz, withInheritance) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList()
override val schemaForDocumentation = Schema(listOf(RestrictedType(nameForType(type), "", listOf(nameForType(type)), SerializerFactory.primitiveTypeName(String::class.java)!!, descriptor, emptyList())))
override fun toProxy(obj: T): String = unmaker(obj)
override fun fromProxy(proxy: String): T = maker(proxy)
override val schemaForDocumentation = Schema(
listOf(RestrictedType(nameForType(type), "", listOf(nameForType(type)),
SerializerFactory.primitiveTypeName(String::class.java)!!,
descriptor, emptyList())))
override fun writeDescribedObject(obj: T, data: Data, type: Type, output: SerializationOutput) {
val proxy = toProxy(obj)
data.putObject(proxy)
data.putObject(unmaker(obj))
}
override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): T {
val proxy = input.readObject(obj, schema, String::class.java) as String
return fromProxy(proxy)
return maker(proxy)
}
}
}

View File

@ -20,7 +20,7 @@ data class ObjectAndEnvelope<out T>(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) {
// TODO: we're not supporting object refs yet
private val objectHistory: MutableList<Any> = ArrayList()

View File

@ -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) {
// TODO: we're not supporting object refs yet
private val objectHistory: MutableMap<Any, Int> = IdentityHashMap()
private val serializerHistory: MutableSet<AMQPSerializer<*>> = LinkedHashSet()

View File

@ -4,7 +4,6 @@ import com.google.common.primitives.Primitives
import com.google.common.reflect.TypeResolver
import net.corda.core.serialization.ClassWhitelist
import net.corda.core.serialization.CordaSerializable
import net.corda.nodeapi.internal.serialization.AllWhitelist
import net.corda.nodeapi.internal.serialization.carpenter.CarpenterSchemas
import net.corda.nodeapi.internal.serialization.carpenter.ClassCarpenter
import net.corda.nodeapi.internal.serialization.carpenter.MetaCarpenter
@ -44,11 +43,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<Type, AMQPSerializer<Any>>()
private val serializersByDescriptor = ConcurrentHashMap<Any, AMQPSerializer<Any>>()
private val customSerializers = CopyOnWriteArrayList<CustomSerializer<out Any>>()
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 +177,18 @@ class SerializerFactory(val whitelist: ClassWhitelist = AllWhitelist) {
}
}
private fun processSchema(schema: Schema, sentinal: Boolean = false) {
/**
* 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, sentinel: Boolean = false) {
val carpenterSchemas = CarpenterSchemas.newInstance()
for (typeNotation in schema.types) {
try {
processSchemaEntry(typeNotation, classCarpenter.classloader)
processSchemaEntry(typeNotation)
} catch (e: ClassNotFoundException) {
if (sentinal || (typeNotation !is CompositeType)) throw e
typeNotation.carpenterSchema(
classLoaders = listOf(classCarpenter.classloader), carpenterSchemas = carpenterSchemas)
if (sentinel || (typeNotation !is CompositeType)) throw e
typeNotation.carpenterSchema(classloader, carpenterSchemas = carpenterSchemas)
}
}
@ -195,24 +199,22 @@ 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
}
}
private fun processRestrictedType(typeNotation: RestrictedType) {
// TODO: class loader logic, and compare the schema.
val type = typeForName(typeNotation.name)
val type = typeForName(typeNotation.name, classloader)
get(null, type)
}
private fun processCompositeType(typeNotation: CompositeType,
cl: ClassLoader = DeserializedParameterizedType::class.java.classLoader) {
private fun processCompositeType(typeNotation: CompositeType) {
// TODO: class loader logic, and compare the schema.
val type = typeForName(typeNotation.name, cl)
val type = typeForName(typeNotation.name, classloader)
get(type.asClass() ?: throw NotSerializableException("Unable to build composite type for $type"), type)
}
@ -322,11 +324,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 +349,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)
}
}
}

View File

@ -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<ClassLoader> = listOf<ClassLoader>(ClassLoader.getSystemClassLoader()))
: CarpenterSchemas {
fun AMQPSchema.carpenterSchema(classloader: ClassLoader) : CarpenterSchemas {
val rtn = CarpenterSchemas.newInstance()
types.filterIsInstance<CompositeType>().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<ClassLoader> = listOf<ClassLoader>(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<ClassLoader> = listOf<ClassLoader>(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<Class<*>>()
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<Pair<String, Boolean>, Class<out Any?>> = mapOf(
Pair("byte", false) to Byte::class.javaObjectType
)
fun AMQPField.getTypeAsClass(
classLoaders: List<ClassLoader> = listOf<ClassLoader>(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<ClassLoader> = listOf<ClassLoader>(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<ClassLoader>.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<ClassLoader>.loadIfExists(clazz: String): Class<*> {
this.forEach {
try {
return it.loadClass(clazz)
} catch (e: ClassNotFoundException) {
return@forEach
}
}
throw ClassNotFoundException(clazz)
}

View File

@ -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<String, Class<*>>()
private val String.jvm: String get() = replace(".", "/")

View File

@ -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> (
ClassLoader.getSystemClassLoader(),
cc.classloader),
classloader = cc.classloader,
carpenterSchemas = schemas)
}
}

View File

@ -1,10 +1,14 @@
package net.corda.nodeapi.internal.serialization.amqp
import org.apache.qpid.proton.codec.Data
import net.corda.nodeapi.internal.serialization.AllWhitelist
fun testDefaultFactory() = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
class TestSerializationOutput(
private val verbose: Boolean,
serializerFactory: SerializerFactory = SerializerFactory()) : SerializationOutput(serializerFactory) {
serializerFactory: SerializerFactory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()))
: SerializationOutput(serializerFactory) {
override fun writeSchema(schema: Schema, data: Data) {
if (verbose) println(schema)

View File

@ -18,7 +18,7 @@ class DeserializeAndReturnEnvelopeTests {
val a = A(10, "20")
val factory = SerializerFactory()
val factory = testDefaultFactory()
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 = testDefaultFactory()
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))

View File

@ -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
@ -16,12 +16,12 @@ class DeserializeNeedingCarpentrySimpleTypesTest {
private const val VERBOSE = false
}
val sf = SerializerFactory()
val sf2 = SerializerFactory()
val sf = testDefaultFactory()
val sf2 = testDefaultFactory()
@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,

View File

@ -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
@ -26,13 +25,13 @@ class DeserializeNeedingCarpentryTests {
private const val VERBOSE = false
}
val sf1 = SerializerFactory()
val sf2 = SerializerFactory()
val sf1 = testDefaultFactory()
val sf2 = testDefaultFactory()
@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<Any>)
@ -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))
@ -195,7 +200,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 +228,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)))

View File

@ -16,30 +16,30 @@ class DeserializeSimpleTypesTests {
private const val VERBOSE = false
}
val sf1 = SerializerFactory()
val sf2 = SerializerFactory()
val sf1 = testDefaultFactory()
val sf2 = testDefaultFactory()
@Test
fun testChar() {
data class C(val c: Char)
var deserializedC = DeserializationInput().deserialize(SerializationOutput().serialize(C('c')))
var deserializedC = DeserializationInput(sf1).deserialize(SerializationOutput(sf1).serialize(C('c')))
assertEquals('c', deserializedC.c)
// CYRILLIC CAPITAL LETTER YU (U+042E)
deserializedC = DeserializationInput().deserialize(SerializationOutput().serialize(C('Ю')))
deserializedC = DeserializationInput(sf1).deserialize(SerializationOutput(sf1).serialize(C('Ю')))
assertEquals('Ю', deserializedC.c)
// ARABIC LETTER FEH WITH DOT BELOW (U+06A3)
deserializedC = DeserializationInput().deserialize(SerializationOutput().serialize(C('ڣ')))
deserializedC = DeserializationInput(sf1).deserialize(SerializationOutput(sf1).serialize(C('ڣ')))
assertEquals('ڣ', deserializedC.c)
// ARABIC LETTER DAD WITH DOT BELOW (U+06FB)
deserializedC = DeserializationInput().deserialize(SerializationOutput().serialize(C('ۻ')))
deserializedC = DeserializationInput(sf1).deserialize(SerializationOutput(sf1).serialize(C('ۻ')))
assertEquals('ۻ', deserializedC.c)
// BENGALI LETTER AA (U+0986)
deserializedC = DeserializationInput().deserialize(SerializationOutput().serialize(C('আ')))
deserializedC = DeserializationInput(sf1).deserialize(SerializationOutput(sf1).serialize(C('আ')))
assertEquals('আ', deserializedC.c)
}
@ -49,8 +49,8 @@ class DeserializeSimpleTypesTests {
data class C(val c: Character)
val c = C(Character('c'))
val serialisedC = SerializationOutput().serialize(c)
val deserializedC = DeserializationInput().deserialize(serialisedC)
val serialisedC = SerializationOutput(sf1).serialize(c)
val deserializedC = DeserializationInput(sf1).deserialize(serialisedC)
assertEquals(c.c, deserializedC.c)
}
@ -60,8 +60,8 @@ class DeserializeSimpleTypesTests {
data class C(val c: Char?)
val c = C(null)
val serialisedC = SerializationOutput().serialize(c)
val deserializedC = DeserializationInput().deserialize(serialisedC)
val serialisedC = SerializationOutput(sf1).serialize(c)
val deserializedC = DeserializationInput(sf1).deserialize(serialisedC)
assertEquals(c.c, deserializedC.c)
}

View File

@ -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<Object> bytes = ser.serialize(obj);

View File

@ -14,7 +14,9 @@ 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.nodeapi.internal.serialization.SerializationFactoryImpl
import net.corda.nodeapi.internal.serialization.AMQPServerSerializationScheme
import net.corda.nodeapi.internal.serialization.AllWhitelist
import net.corda.testing.MEGA_CORP
import net.corda.testing.MEGA_CORP_PUBKEY
import org.apache.qpid.proton.amqp.*
@ -136,8 +138,10 @@ class SerializationOutputTests {
data class PolymorphicProperty(val foo: FooInterface?)
private fun serdes(obj: Any,
factory: SerializerFactory = SerializerFactory(),
freshDeserializationFactory: SerializerFactory = SerializerFactory(),
factory: SerializerFactory = SerializerFactory (
AllWhitelist, ClassLoader.getSystemClassLoader()),
freshDeserializationFactory: SerializerFactory = SerializerFactory(
AllWhitelist, ClassLoader.getSystemClassLoader()),
expectedEqual: Boolean = true,
expectDeserializedEqual: Boolean = true): Any {
val ser = SerializationOutput(factory)
@ -285,13 +289,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 +391,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 +402,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 +420,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 +451,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 +473,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 +485,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,12 +529,12 @@ class SerializationOutputTests {
@Test
fun `test transaction state`() {
val state = TransactionState<FooState>(FooState(), MEGA_CORP)
val state = TransactionState(FooState(), MEGA_CORP)
val factory = SerializerFactory()
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
AbstractAMQPSerializationScheme.registerCustomSerializers(factory)
val factory2 = SerializerFactory()
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
AbstractAMQPSerializationScheme.registerCustomSerializers(factory2)
val desState = serdes(state, factory, factory2, expectedEqual = false, expectDeserializedEqual = false)
@ -542,11 +546,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 +558,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 +570,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 +582,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)

View File

@ -1,11 +1,8 @@
package net.corda.nodeapi.internal.serialization.carpenter
import net.corda.nodeapi.internal.serialization.amqp.*
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
fun mangleName(name: String) = "${name}__carpenter"
@ -37,7 +34,7 @@ fun Schema.mangleNames(names: List<String>): Schema {
}
open class AmqpCarpenterBase {
var factory = SerializerFactory()
var factory = testDefaultFactory()
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
fun testName(): String = Thread.currentThread().stackTrace[2].methodName

View File

@ -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()))
}
/*

View File

@ -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)

View File

@ -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") }

View File

@ -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)