Refactoring changes to work with interface changes

Specifically we don't need the factory factory as that functionality
lives in the global defaults
This commit is contained in:
Katelyn Baker
2017-08-15 14:14:21 +01:00
parent 139eef2ccb
commit 825908cf15
11 changed files with 55 additions and 78 deletions

View File

@ -47,8 +47,9 @@ abstract class AbstractAMQPSerializationScheme : SerializationScheme {
} }
fun getSerializerFactory(): SerializerFactory { fun getSerializerFactory(): SerializerFactory {
return serializerFactoriesForContexts.computeIfAbsent(Pair(AllWhitelist, deserializationClassLoader)) { return serializerFactoriesForContexts.computeIfAbsent(Pair(
SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader()) AllWhitelist, SerializationDefaults.javaClass.classLoader)) {
SerializerFactory(AllWhitelist, SerializationDefaults.javaClass.classLoader)
} }
} }

View File

@ -6,13 +6,9 @@ import com.esotericsoftware.kryo.io.Input
import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.io.Output
import net.corda.core.serialization.SerializationContext import net.corda.core.serialization.SerializationContext
import net.corda.core.serialization.SerializationFactory import net.corda.core.serialization.SerializationFactory
import net.corda.core.serialization.SerializedBytes
import net.corda.core.utilities.sequence import net.corda.core.utilities.sequence
import net.corda.nodeapi.internal.serialization.amqp.AmqpHeaderV1_0 import net.corda.nodeapi.internal.serialization.amqp.AmqpHeaderV1_0
import net.corda.nodeapi.internal.serialization.amqp.DeserializationInput 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` * This [Kryo] custom [Serializer] switches the object graph of anything annotated with `@CordaSerializable`

View File

@ -1,5 +1,6 @@
package net.corda.nodeapi.internal.serialization.amqp package net.corda.nodeapi.internal.serialization.amqp
import net.corda.core.serialization.SerializationDefaults
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.nameForType import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.nameForType
import org.apache.qpid.proton.codec.Data import org.apache.qpid.proton.codec.Data
import java.lang.reflect.Type 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>() { abstract class CustomSerializerImp<T>(protected val clazz: Class<T>, protected val withInheritance: Boolean) : CustomSerializer<T>() {
override fun isSerializerFor(clazz: Class<*>): Boolean = clazz == this.clazz
override val type: Type get() = clazz override val type: Type get() = clazz
override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${nameForType(clazz)}" override val typeDescriptor: String = "$DESCRIPTOR_DOMAIN:${nameForType(clazz)}"
override fun writeClassInfo(output: SerializationOutput) {} override fun writeClassInfo(output: SerializationOutput) {}
override val descriptor: Descriptor = Descriptor(typeDescriptor) 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. * 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>() { abstract class Implements<T>(clazz: Class<T>) : CustomSerializerImp<T>(clazz, true)
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)
}
/** /**
* Additional base features over and above [Implements] or [Is] custom serializer for when the serialized form should be * 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 * The proxy class must use only types which are either native AMQP or other types for which there are pre-registered
* custom serializers. * 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 proxyClass: Class<P>,
protected val factory: SerializerFactory, 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 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) } private val proxySerializer: ObjectSerializer by lazy { ObjectSerializer(proxyClass, factory) }
@ -152,26 +149,26 @@ abstract class CustomSerializer<T> : AMQPSerializer<T> {
*/ */
abstract class ToString<T>(clazz: Class<T>, withInheritance: Boolean = false, abstract class ToString<T>(clazz: Class<T>, withInheritance: Boolean = false,
private val maker: (String) -> T = clazz.getConstructor(String::class.java).let { private val maker: (String) -> T = clazz.getConstructor(String::class.java).let {
`constructor` -> { string -> `constructor`.newInstance(string) } `constructor` ->
{ string -> `constructor`.newInstance(string) }
}, },
private val unmaker: (T) -> String = { obj -> obj.toString() }) : Proxy<T, String>(clazz, String::class.java, /* Unused */ SerializerFactoryFactory.get(), withInheritance) { private val unmaker: (T) -> String = { obj -> obj.toString() })
: CustomSerializerImp<T>(clazz, withInheritance) {
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = emptyList() 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 val schemaForDocumentation = Schema(
listOf(RestrictedType(nameForType(type), "", listOf(nameForType(type)),
override fun toProxy(obj: T): String = unmaker(obj) SerializerFactory.primitiveTypeName(String::class.java)!!,
descriptor, emptyList())))
override fun fromProxy(proxy: String): T = maker(proxy)
override fun writeDescribedObject(obj: T, data: Data, type: Type, output: SerializationOutput) { override fun writeDescribedObject(obj: T, data: Data, type: Type, output: SerializationOutput) {
val proxy = toProxy(obj) data.putObject(unmaker(obj))
data.putObject(proxy)
} }
override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): T { override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): T {
val proxy = input.readObject(obj, schema, String::class.java) as String 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 * @param serializerFactory This is the factory for [AMQPSerializer] instances and can be shared across multiple
* instances and threads. * instances and threads.
*/ */
class DeserializationInput(internal val serializerFactory: SerializerFactory = SerializerFactoryFactory.get()) { class DeserializationInput(internal val serializerFactory: SerializerFactory) {
// TODO: we're not supporting object refs yet // TODO: we're not supporting object refs yet
private val objectHistory: MutableList<Any> = ArrayList() 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 * @param serializerFactory This is the factory for [AMQPSerializer] instances and can be shared across multiple
* instances and threads. * instances and threads.
*/ */
open class SerializationOutput(internal val serializerFactory: SerializerFactory = SerializerFactoryFactory.get()) { open class SerializationOutput(internal val serializerFactory: SerializerFactory) {
// TODO: we're not supporting object refs yet // TODO: we're not supporting object refs yet
private val objectHistory: MutableMap<Any, Int> = IdentityHashMap() private val objectHistory: MutableMap<Any, Int> = IdentityHashMap()
private val serializerHistory: MutableSet<AMQPSerializer<*>> = LinkedHashSet() private val serializerHistory: MutableSet<AMQPSerializer<*>> = LinkedHashSet()

View File

@ -1,22 +0,0 @@
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<Pair<ClassWhitelist, ClassLoader>, 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())
}
}

View File

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

View File

@ -18,7 +18,7 @@ class DeserializeAndReturnEnvelopeTests {
val a = A(10, "20") val a = A(10, "20")
val factory = SerializerFactoryFactory.get() val factory = testDefaultFactory()
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz) fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a)) val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
@ -34,7 +34,7 @@ class DeserializeAndReturnEnvelopeTests {
val b = B(A(10, "20"), 30.0F) val b = B(A(10, "20"), 30.0F)
val factory = SerializerFactoryFactory.get() val factory = testDefaultFactory()
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz) fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b)) val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))

View File

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

View File

@ -14,6 +14,9 @@ import net.corda.nodeapi.RPCException
import net.corda.nodeapi.internal.serialization.AbstractAMQPSerializationScheme import net.corda.nodeapi.internal.serialization.AbstractAMQPSerializationScheme
import net.corda.nodeapi.internal.serialization.EmptyWhitelist import net.corda.nodeapi.internal.serialization.EmptyWhitelist
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.isPrimitive import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.Companion.isPrimitive
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
import net.corda.testing.MEGA_CORP_PUBKEY import net.corda.testing.MEGA_CORP_PUBKEY
import org.apache.qpid.proton.amqp.* import org.apache.qpid.proton.amqp.*
@ -135,7 +138,8 @@ class SerializationOutputTests {
data class PolymorphicProperty(val foo: FooInterface?) data class PolymorphicProperty(val foo: FooInterface?)
private fun serdes(obj: Any, private fun serdes(obj: Any,
factory: SerializerFactory = SerializerFactoryFactory.get(), factory: SerializerFactory = SerializerFactory (
AllWhitelist, ClassLoader.getSystemClassLoader()),
freshDeserializationFactory: SerializerFactory = SerializerFactory( freshDeserializationFactory: SerializerFactory = SerializerFactory(
AllWhitelist, ClassLoader.getSystemClassLoader()), AllWhitelist, ClassLoader.getSystemClassLoader()),
expectedEqual: Boolean = true, expectedEqual: Boolean = true,
@ -527,10 +531,10 @@ class SerializationOutputTests {
fun `test transaction state`() { fun `test transaction state`() {
val state = TransactionState(FooState(), MEGA_CORP) val state = TransactionState(FooState(), MEGA_CORP)
val factory = SerializerFactory() val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
AbstractAMQPSerializationScheme.registerCustomSerializers(factory) AbstractAMQPSerializationScheme.registerCustomSerializers(factory)
val factory2 = SerializerFactory() val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
AbstractAMQPSerializationScheme.registerCustomSerializers(factory2) AbstractAMQPSerializationScheme.registerCustomSerializers(factory2)
val desState = serdes(state, factory, factory2, expectedEqual = false, expectDeserializedEqual = false) val desState = serdes(state, factory, factory2, expectedEqual = false, expectDeserializedEqual = false)

View File

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