mirror of
https://github.com/corda/corda.git
synced 2024-12-23 14:52:29 +00:00
Review Comments
Refactor small bits of the serialiser, move things out of the read methods and into the make factory companion object
This commit is contained in:
parent
299b8026c7
commit
cf9fbc715d
@ -6,6 +6,6 @@ package net.corda.core.serialization
|
|||||||
*/
|
*/
|
||||||
@Target(AnnotationTarget.CONSTRUCTOR)
|
@Target(AnnotationTarget.CONSTRUCTOR)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
annotation class CordaSerializerConstructor(val version: Int)
|
annotation class EvolvedSerializerConstructor(val version: Int)
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
package net.corda.nodeapi.internal.serialization.amqp
|
package net.corda.nodeapi.internal.serialization.amqp
|
||||||
|
|
||||||
import net.corda.core.serialization.CordaSerializerConstructor
|
import net.corda.core.serialization.EvolvedSerializerConstructor
|
||||||
import net.corda.nodeapi.internal.serialization.carpenter.getTypeAsClass
|
import net.corda.nodeapi.internal.serialization.carpenter.getTypeAsClass
|
||||||
import org.apache.qpid.proton.codec.Data
|
import org.apache.qpid.proton.codec.Data
|
||||||
import java.lang.reflect.Type
|
import java.lang.reflect.Type
|
||||||
@ -16,7 +16,8 @@ import kotlin.reflect.jvm.javaType
|
|||||||
class EvolutionSerializer(
|
class EvolutionSerializer(
|
||||||
clazz: Type,
|
clazz: Type,
|
||||||
factory: SerializerFactory,
|
factory: SerializerFactory,
|
||||||
val oldParams : Map<String, oldParam>,
|
val oldParams : Map<String, OldParam>,
|
||||||
|
val newParams : Map<String, Boolean>,
|
||||||
override val kotlinConstructor: KFunction<Any>?) : ObjectSerializer (clazz, factory) {
|
override val kotlinConstructor: KFunction<Any>?) : ObjectSerializer (clazz, factory) {
|
||||||
|
|
||||||
// explicitly null this out as we won't be using this list
|
// explicitly null this out as we won't be using this list
|
||||||
@ -31,7 +32,10 @@ class EvolutionSerializer(
|
|||||||
* order may have been changed and we need to know where into the list to look
|
* order may have been changed and we need to know where into the list to look
|
||||||
* @param property object to read the actual property value
|
* @param property object to read the actual property value
|
||||||
*/
|
*/
|
||||||
data class oldParam (val type: Type, val idx: Int, val property: PropertySerializer)
|
data class OldParam (val type: Type, val idx: Int, val property: PropertySerializer) {
|
||||||
|
fun readProperty(paramValues: List<*>, schema: Schema, input: DeserializationInput) =
|
||||||
|
property.readProperty(paramValues[idx], schema, input)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
@ -53,7 +57,7 @@ class EvolutionSerializer(
|
|||||||
var maxConstructorVersion = Integer.MIN_VALUE
|
var maxConstructorVersion = Integer.MIN_VALUE
|
||||||
var constructor: KFunction<Any>? = null
|
var constructor: KFunction<Any>? = null
|
||||||
clazz.kotlin.constructors.forEach {
|
clazz.kotlin.constructors.forEach {
|
||||||
val version = it.findAnnotation<CordaSerializerConstructor>()?.version ?: Integer.MIN_VALUE
|
val version = it.findAnnotation<EvolvedSerializerConstructor>()?.version ?: Integer.MIN_VALUE
|
||||||
if (oldArgumentSet.containsAll(it.parameters.map { v -> Pair(v.name, v.type.javaType) }) &&
|
if (oldArgumentSet.containsAll(it.parameters.map { v -> Pair(v.name, v.type.javaType) }) &&
|
||||||
version > maxConstructorVersion) {
|
version > maxConstructorVersion) {
|
||||||
constructor = it
|
constructor = it
|
||||||
@ -67,7 +71,7 @@ class EvolutionSerializer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a serialization object for deserialisation only of objects serislaised
|
* Build a serialization object for deserialisation only of objects serialised
|
||||||
* as different versions of a class
|
* as different versions of a class
|
||||||
*
|
*
|
||||||
* @param old is an object holding the schema that represents the object
|
* @param old is an object holding the schema that represents the object
|
||||||
@ -86,15 +90,17 @@ class EvolutionSerializer(
|
|||||||
throw NotSerializableException(
|
throw NotSerializableException(
|
||||||
"Attempt to deserialize an interface: new.type. Serialized form is invalid.")
|
"Attempt to deserialize an interface: new.type. Serialized form is invalid.")
|
||||||
|
|
||||||
val oldArgs = mutableMapOf<String, oldParam>()
|
val oldArgs = mutableMapOf<String, OldParam>()
|
||||||
var idx = 0
|
var idx = 0
|
||||||
old.fields.forEach {
|
old.fields.forEach {
|
||||||
val returnType = it.getTypeAsClass(factory.classloader)
|
val returnType = it.getTypeAsClass(factory.classloader)
|
||||||
oldArgs[it.name] = oldParam(
|
oldArgs[it.name] = OldParam(
|
||||||
returnType, idx++, PropertySerializer.make(it.name, null, returnType, factory))
|
returnType, idx++, PropertySerializer.make(it.name, null, returnType, factory))
|
||||||
}
|
}
|
||||||
|
|
||||||
return EvolutionSerializer(new.type, factory, oldArgs, constructor)
|
val newArgs = constructor.parameters.associateBy({ it.name!! }, {it.type.isMarkedNullable})
|
||||||
|
|
||||||
|
return EvolutionSerializer(new.type, factory, oldArgs, newArgs, constructor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,17 +118,14 @@ class EvolutionSerializer(
|
|||||||
override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): Any {
|
override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): Any {
|
||||||
if (obj !is List<*>) throw NotSerializableException("Body of described type is unexpected $obj")
|
if (obj !is List<*>) throw NotSerializableException("Body of described type is unexpected $obj")
|
||||||
|
|
||||||
val newArgs = kotlinConstructor?.parameters?.associateBy({ it.name!! }, {it.type.isMarkedNullable}) ?:
|
return construct(newParams.map {
|
||||||
throw NotSerializableException ("Bad Constructor selected for object $obj")
|
|
||||||
|
|
||||||
return construct(newArgs.map {
|
|
||||||
val param = oldParams[it.key]
|
val param = oldParams[it.key]
|
||||||
if (param == null && !it.value) {
|
if (param == null && !it.value) {
|
||||||
throw NotSerializableException(
|
throw NotSerializableException(
|
||||||
"New parameter ${it.key} is mandatory, should be nullable for evolution to worK")
|
"New parameter ${it.key} is mandatory, should be nullable for evolution to worK")
|
||||||
}
|
}
|
||||||
|
|
||||||
param?.property?.readProperty(obj[param.idx], schema, input)
|
param?.readProperty(obj, schema, input)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ open class ObjectSerializer(val clazz: Type, factory: SerializerFactory) : AMQPS
|
|||||||
override val type: Type get() = clazz
|
override val type: Type get() = clazz
|
||||||
open internal val propertySerializers: Collection<PropertySerializer>
|
open internal val propertySerializers: Collection<PropertySerializer>
|
||||||
open val kotlinConstructor = constructorForDeserialization(clazz)
|
open val kotlinConstructor = constructorForDeserialization(clazz)
|
||||||
|
val javaConstructor by lazy { kotlinConstructor?.javaConstructor }
|
||||||
|
|
||||||
init {
|
init {
|
||||||
propertySerializers = propertiesForSerialization(kotlinConstructor, clazz, factory)
|
propertySerializers = propertiesForSerialization(kotlinConstructor, clazz, factory)
|
||||||
@ -71,9 +72,10 @@ open class ObjectSerializer(val clazz: Type, factory: SerializerFactory) : AMQPS
|
|||||||
|
|
||||||
|
|
||||||
fun construct(properties: List<Any?>): Any {
|
fun construct(properties: List<Any?>): Any {
|
||||||
val javaConstructor = kotlinConstructor?.javaConstructor ?:
|
if (javaConstructor == null) {
|
||||||
throw NotSerializableException("Attempt to deserialize an interface: $clazz. Serialized form is invalid.")
|
throw NotSerializableException("Attempt to deserialize an interface: $clazz. Serialized form is invalid.")
|
||||||
|
}
|
||||||
|
|
||||||
return javaConstructor.newInstance(*properties.toTypedArray())
|
return javaConstructor!!.newInstance(*properties.toTypedArray())
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -191,8 +191,8 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl : ClassLoader) {
|
|||||||
val serialiser = processSchemaEntry(typeNotation)
|
val serialiser = processSchemaEntry(typeNotation)
|
||||||
|
|
||||||
// if we just successfully built a serialiser for the type but the type fingerprint
|
// if we just successfully built a serialiser for the type but the type fingerprint
|
||||||
// doesn't match that of the serialised object then we are dealing with an older
|
// doesn't match that of the serialised object then we are dealing with different
|
||||||
// instance of the class, as such we need to build an evolverSerilaiser
|
// instance of the class, as such we need to build an EvolutionSerialiser
|
||||||
if (serialiser.typeDescriptor != typeNotation.descriptor.name) {
|
if (serialiser.typeDescriptor != typeNotation.descriptor.name) {
|
||||||
getEvolutionSerializer(typeNotation, serialiser as ObjectSerializer)
|
getEvolutionSerializer(typeNotation, serialiser as ObjectSerializer)
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
package net.corda.nodeapi.internal.serialization.amqp
|
package net.corda.nodeapi.internal.serialization.amqp
|
||||||
|
|
||||||
import net.corda.core.serialization.SerializedBytes
|
import net.corda.core.serialization.SerializedBytes
|
||||||
import net.corda.core.serialization.CordaSerializerConstructor
|
import net.corda.core.serialization.EvolvedSerializerConstructor
|
||||||
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.NotSerializableException
|
import java.io.NotSerializableException
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
// To regenerate any of the binary test files do the following
|
||||||
|
//
|
||||||
|
// 1. Uncomment the code where the original form of the class is defined in the test
|
||||||
|
// 2. Comment out the rest of the test
|
||||||
|
// 3. Run the test
|
||||||
|
// 4. Using the printed path copy that file to the resources directory
|
||||||
|
// 5. Comment back out the generation code and uncomment the actual test
|
||||||
class EvolvabilityTests {
|
class EvolvabilityTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -104,7 +111,7 @@ class EvolvabilityTests {
|
|||||||
|
|
||||||
// Expected to throw as we can't construct the new type as it contains a newly
|
// Expected to throw as we can't construct the new type as it contains a newly
|
||||||
// added parameter that isn't optional, i.e. not nullable and there isn't
|
// added parameter that isn't optional, i.e. not nullable and there isn't
|
||||||
// a compiler that takes the old parameters
|
// a constructor that takes the old parameters
|
||||||
DeserializationInput(sf).deserialize(SerializedBytes<C>(sc2))
|
DeserializationInput(sf).deserialize(SerializedBytes<C>(sc2))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +187,7 @@ class EvolvabilityTests {
|
|||||||
|
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
data class CC (val a: Int, val b: String) {
|
data class CC (val a: Int, val b: String) {
|
||||||
@CordaSerializerConstructor(1)
|
@EvolvedSerializerConstructor(1)
|
||||||
constructor (a: Int) : this (a, "hello")
|
constructor (a: Int) : this (a, "hello")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +246,7 @@ class EvolvabilityTests {
|
|||||||
data class CC (val a: Int, val b: Int, val c: String, val d: String) {
|
data class CC (val a: Int, val b: Int, val c: String, val d: String) {
|
||||||
// ensure none of the original parameters align with the initial
|
// ensure none of the original parameters align with the initial
|
||||||
// construction order
|
// construction order
|
||||||
@CordaSerializerConstructor(1)
|
@EvolvedSerializerConstructor(1)
|
||||||
constructor (c: String, a: Int, b: Int) : this (a, b, c, "wibble")
|
constructor (c: String, a: Int, b: Int) : this (a, b, c, "wibble")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +282,7 @@ class EvolvabilityTests {
|
|||||||
// ensure none of the original parameters align with the initial
|
// ensure none of the original parameters align with the initial
|
||||||
// construction order
|
// construction order
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
@CordaSerializerConstructor(1)
|
@EvolvedSerializerConstructor(1)
|
||||||
constructor (c: String, a: Int) : this (a, c, "wibble")
|
constructor (c: String, a: Int) : this (a, c, "wibble")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,11 +324,11 @@ class EvolvabilityTests {
|
|||||||
|
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
data class C (val e: Int, val c: Int, val b: Int, val a: Int, val d: Int) {
|
data class C (val e: Int, val c: Int, val b: Int, val a: Int, val d: Int) {
|
||||||
@CordaSerializerConstructor(1)
|
@EvolvedSerializerConstructor(1)
|
||||||
constructor (b: Int, a: Int) : this (-1, -1, b, a, -1)
|
constructor (b: Int, a: Int) : this (-1, -1, b, a, -1)
|
||||||
@CordaSerializerConstructor(2)
|
@EvolvedSerializerConstructor(2)
|
||||||
constructor (a: Int, c: Int, b: Int) : this (-1, c, b, a, -1)
|
constructor (a: Int, c: Int, b: Int) : this (-1, c, b, a, -1)
|
||||||
@CordaSerializerConstructor(3)
|
@EvolvedSerializerConstructor(3)
|
||||||
constructor (a: Int, b: Int, c: Int, d: Int) : this (-1, c, b, a, d)
|
constructor (a: Int, b: Int, c: Int, d: Int) : this (-1, c, b, a, d)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,13 +418,13 @@ class EvolvabilityTests {
|
|||||||
|
|
||||||
@Suppress("UNUSED")
|
@Suppress("UNUSED")
|
||||||
data class C (val b: Int, val c: Int, val d: Int, val e: Int, val f: Int, val g: Int) {
|
data class C (val b: Int, val c: Int, val d: Int, val e: Int, val f: Int, val g: Int) {
|
||||||
@CordaSerializerConstructor(1)
|
@EvolvedSerializerConstructor(1)
|
||||||
constructor (b: Int, c: Int) : this (b, c, -1, -1, -1, -1)
|
constructor (b: Int, c: Int) : this (b, c, -1, -1, -1, -1)
|
||||||
@CordaSerializerConstructor(2)
|
@EvolvedSerializerConstructor(2)
|
||||||
constructor (b: Int, c: Int, d: Int) : this (b, c, d, -1, -1, -1)
|
constructor (b: Int, c: Int, d: Int) : this (b, c, d, -1, -1, -1)
|
||||||
@CordaSerializerConstructor(3)
|
@EvolvedSerializerConstructor(3)
|
||||||
constructor (b: Int, c: Int, d: Int, e: Int) : this (b, c, d, e, -1, -1)
|
constructor (b: Int, c: Int, d: Int, e: Int) : this (b, c, d, e, -1, -1)
|
||||||
@CordaSerializerConstructor(4)
|
@EvolvedSerializerConstructor(4)
|
||||||
constructor (b: Int, c: Int, d: Int, e: Int, f: Int) : this (b, c, d, e, f, -1)
|
constructor (b: Int, c: Int, d: Int, e: Int, f: Int) : this (b, c, d, e, f, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user