CORDA-553 - Cope with future transforms

This commit is contained in:
Katelyn Baker 2017-10-26 16:54:36 +01:00
parent bc12f87a24
commit 3350605536
22 changed files with 198 additions and 118 deletions

View File

@ -57,6 +57,7 @@ data class Envelope(val obj: Any?, val schema: Schema, val transformsSchema: Tra
ENVELOPE_WITH_TRANSFORMS -> list[TRANSFORMS_SCHEMA_IDX] as TransformsSchema
else -> throw NotSerializableException("Malformed list, bad length of ${list.size} (should be 2 or 3)")
}
return Envelope(list[BLOB_IDX], list[SCHEMA_IDX] as Schema, transformSchema)
}

View File

@ -36,11 +36,17 @@ private val wrapperExtract = { x: Annotation ->
*/
private val singleExtract = { x: Annotation -> listOf(x) }
// Transform annotation used to test the handling of transforms the de-serialising node doesn't understand. At
// some point test cases will have been created with this transform applied.
//@Target(AnnotationTarget.CLASS)
//@Retention(AnnotationRetention.RUNTIME)
//annotation class UnknownTransformAnnotation(val a: Int, val b: Int, val c: Int)
/**
* Utility list of all transforms we support that simplifies our generation code
* Utility list of all transforms we support that simplifies our generation code.
*
* NOTE: We have to support single instances of the transform annotations as well as the wrapping annotation
* when many instances are repeated
* when many instances are repeated.
*/
val supportedTransforms = listOf(
SupportedTransform(
@ -63,4 +69,8 @@ val supportedTransforms = listOf(
TransformTypes.Rename,
singleExtract
)
//,SupportedTransform(
// UnknownTransformAnnotation::class.java,
// TransformTypes.UnknownTest,
// singleExtract)
)

View File

@ -14,11 +14,21 @@ import java.io.NotSerializableException
* @property build should be a function that takes a transform [Annotation] (currently one of
* [CordaSerializationTransformRename] or [CordaSerializationTransformEnumDefaults])
* and constructs an instance of the corresponding [Transform] type
*
* DO NOT REORDER THE CONSTANTS!!! Please append any new entries to the end
*/
// TODO: it would be awesome to auto build this list by scanning for transform annotations themselves
// TODO: annotated with some annotation
enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType {
EnumDefault({ a -> EnumDefaultSchemeTransform((a as CordaSerializationTransformEnumDefault).old, a.new) }) {
/**
* Placeholder entry for future transforms where a node receives a transform we've subsequently
* added and thus the de-serialising node doesn't know about that transform.
*/
Unknown({ UnknownTransform() }) {
override fun getDescriptor(): Any = DESCRIPTOR
override fun getDescribed(): Any = ordinal
},
EnumDefault({ a -> EnumDefaultSchemaTransform((a as CordaSerializationTransformEnumDefault).old, a.new) }) {
override fun getDescriptor(): Any = DESCRIPTOR
override fun getDescribed(): Any = ordinal
},
@ -26,6 +36,13 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType
override fun getDescriptor(): Any = DESCRIPTOR
override fun getDescribed(): Any = ordinal
};
// Transform used to test the unknown handler, leave this at as the final constant, uncomment
// when regenerating test cases - if Java had a pre-processor this would be much neater
//
//UnknownTest({ a -> UnknownTestTransform((a as UnknownTransformAnnotation).a, a.b, a.c)}) {
// override fun getDescriptor(): Any = DESCRIPTOR
// override fun getDescribed(): Any = ordinal
//};
companion object : DescribedTypeConstructor<TransformTypes> {
val DESCRIPTOR = AMQPDescriptorRegistry.TRANSFORM_ELEMENT_KEY.amqpDescriptor
@ -42,10 +59,10 @@ enum class TransformTypes(val build: (Annotation) -> Transform) : DescribedType
throw NotSerializableException("Unexpected descriptor ${describedType.descriptor}.")
}
try {
return values()[describedType.described as Int]
return try {
values()[describedType.described as Int]
} catch (e: IndexOutOfBoundsException) {
throw NotSerializableException("Bad ordinal value ${describedType.described}.")
values()[0]
}
}

View File

@ -37,15 +37,18 @@ abstract class Transform : DescribedType {
* the schema as a list of class name and parameters.Using the class name (list element 0)
* create the appropriate class instance
*
* For future proofing any unknown transform types are not treated as errors, rather we
* simply create a placeholder object so we can ignore it
*
* @param obj: a serialized instance of a described type, should be one of the
* descendants of this class
*/
override fun newInstance(obj: Any?): Transform {
val described = Transform.checkDescribed(obj) as List<*>
return when (described[0]) {
EnumDefaultSchemeTransform.typeName -> EnumDefaultSchemeTransform.newInstance(described)
EnumDefaultSchemaTransform.typeName -> EnumDefaultSchemaTransform.newInstance(described)
RenameSchemaTransform.typeName -> RenameSchemaTransform.newInstance(described)
else -> throw NotSerializableException("Unexpected transform type ${described[0]}")
else -> UnknownTransform()
}
}
@ -63,27 +66,64 @@ abstract class Transform : DescribedType {
abstract val name: String
}
/**
* Transform type placeholder that allows for backward compatibility. Should a noce recieve
* a transform type it doesn't recognise, we can will use this as a placeholder
*/
class UnknownTransform : Transform() {
companion object : DescribedTypeConstructor<UnknownTransform> {
val typeName = "UnknownTransform"
override fun newInstance(obj: Any?) = UnknownTransform()
override fun getTypeClass(): Class<*> = UnknownTransform::class.java
}
override fun getDescribed(): Any = emptyList<Any>()
override fun params() = ""
override val name: String get() = typeName
}
class UnknownTestTransform(val a: Int, val b: Int, val c: Int) : Transform() {
companion object : DescribedTypeConstructor<UnknownTestTransform> {
val typeName = "UnknownTest"
override fun newInstance(obj: Any?) : UnknownTestTransform {
val described = obj as List<*>
return UnknownTestTransform(described[1] as Int, described[2] as Int, described[3] as Int)
}
override fun getTypeClass(): Class<*> = UnknownTransform::class.java
}
override fun getDescribed(): Any = listOf(name, a, b, c)
override fun params() = ""
override val name: String get() = typeName
}
/**
* Transform to be used on an Enumerated Type whenever a new element is added
*
* @property old The value the [new] instance should default to when not available
* @property new the value (as a String) that has been added
*/
class EnumDefaultSchemeTransform(val old: String, val new: String) : Transform() {
companion object : DescribedTypeConstructor<EnumDefaultSchemeTransform> {
class EnumDefaultSchemaTransform(val old: String, val new: String) : Transform() {
companion object : DescribedTypeConstructor<EnumDefaultSchemaTransform> {
/**
* Value encoded into the schema that identifies a transform as this type
*/
val typeName = "EnumDefault"
override fun newInstance(obj: Any?): EnumDefaultSchemeTransform {
override fun newInstance(obj: Any?): EnumDefaultSchemaTransform {
val described = obj as List<*>
val old = described[1] as? String ?: throw IllegalStateException("Was expecting \"old\" as a String")
val new = described[2] as? String ?: throw IllegalStateException("Was expecting \"new\" as a String")
return EnumDefaultSchemeTransform(old, new)
return EnumDefaultSchemaTransform(old, new)
}
override fun getTypeClass(): Class<*> = EnumDefaultSchemeTransform::class.java
override fun getTypeClass(): Class<*> = EnumDefaultSchemaTransform::class.java
}
@Suppress("UNUSED")
@ -93,7 +133,7 @@ class EnumDefaultSchemeTransform(val old: String, val new: String) : Transform()
override fun params() = "old=${old.esc()} new=${new.esc()}"
override fun equals(other: Any?) = (
(other is EnumDefaultSchemeTransform && other.new == new && other.old == old) || super.equals(other))
(other is EnumDefaultSchemaTransform && other.new == new && other.old == old) || super.equals(other))
override fun hashCode() = (17 * new.hashCode()) + old.hashCode()
@ -138,7 +178,6 @@ class RenameSchemaTransform(val from: String, val to: String) : Transform() {
override val name: String get() = typeName
}
/**
* Represents the set of all transforms that can be a applied to all classes represented as part of
* an AMQP schema. It forms a part of the AMQP envelope alongside the [Schema] and the serialized bytes

View File

@ -1,16 +1,19 @@
package net.corda.nodeapi.internal.serialization.amqp
import net.corda.core.serialization.CordaSerializationTransformEnumDefault
import net.corda.core.serialization.CordaSerializationTransformEnumDefaults
import net.corda.core.serialization.CordaSerializationTransformRename
import net.corda.core.serialization.CordaSerializationTransformRenames
import net.corda.core.serialization.*
import org.assertj.core.api.Assertions
import org.junit.Test
import java.io.File
import java.io.NotSerializableException
import java.net.URI
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class EnumEvolvabilityTests {
// var localPath = "file:///Users/katelynbaker/srcs-ide/corda/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp"
var localPath = "file:///home/katelyn/srcs/corda/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp"
companion object {
val VERBOSE = false
}
@ -104,9 +107,9 @@ class EnumEvolvabilityTests {
assertEquals(1, schema.size)
assertTrue (schema.keys.contains(TransformTypes.EnumDefault))
assertEquals (1, schema[TransformTypes.EnumDefault]!!.size)
assertTrue (schema[TransformTypes.EnumDefault]!![0] is EnumDefaultSchemeTransform)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).new)
assertEquals ("A", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).old)
assertTrue (schema[TransformTypes.EnumDefault]!![0] is EnumDefaultSchemaTransform)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).new)
assertEquals ("A", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).old)
}
@Test
@ -125,12 +128,12 @@ class EnumEvolvabilityTests {
assertEquals(1, schema.size)
assertTrue (schema.keys.contains(TransformTypes.EnumDefault))
assertEquals (2, schema[TransformTypes.EnumDefault]!!.size)
assertTrue (schema[TransformTypes.EnumDefault]!![0] is EnumDefaultSchemeTransform)
assertEquals ("E", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).new)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).old)
assertTrue (schema[TransformTypes.EnumDefault]!![1] is EnumDefaultSchemeTransform)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![1] as EnumDefaultSchemeTransform).new)
assertEquals ("A", (schema[TransformTypes.EnumDefault]!![1] as EnumDefaultSchemeTransform).old)
assertTrue (schema[TransformTypes.EnumDefault]!![0] is EnumDefaultSchemaTransform)
assertEquals ("E", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).new)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).old)
assertTrue (schema[TransformTypes.EnumDefault]!![1] is EnumDefaultSchemaTransform)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![1] as EnumDefaultSchemaTransform).new)
assertEquals ("A", (schema[TransformTypes.EnumDefault]!![1] as EnumDefaultSchemaTransform).old)
}
@Test
@ -157,9 +160,9 @@ class EnumEvolvabilityTests {
assertTrue (schema!!.keys.contains(TransformTypes.EnumDefault))
assertEquals (1, schema[TransformTypes.EnumDefault]!!.size)
assertTrue (schema[TransformTypes.EnumDefault]!![0] is EnumDefaultSchemeTransform)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).new)
assertEquals ("A", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).old)
assertTrue (schema[TransformTypes.EnumDefault]!![0] is EnumDefaultSchemaTransform)
assertEquals ("D", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).new)
assertEquals ("A", (schema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).old)
}
@Test
@ -183,10 +186,10 @@ class EnumEvolvabilityTests {
val enumDefaults = transforms[AnnotatedEnumTwice::class.java.name]!![TransformTypes.EnumDefault]!!
assertEquals("E", (enumDefaults[0] as EnumDefaultSchemeTransform).new)
assertEquals("D", (enumDefaults[0] as EnumDefaultSchemeTransform).old)
assertEquals("D", (enumDefaults[1] as EnumDefaultSchemeTransform).new)
assertEquals("A", (enumDefaults[1] as EnumDefaultSchemeTransform).old)
assertEquals("E", (enumDefaults[0] as EnumDefaultSchemaTransform).new)
assertEquals("D", (enumDefaults[0] as EnumDefaultSchemaTransform).old)
assertEquals("D", (enumDefaults[1] as EnumDefaultSchemaTransform).new)
assertEquals("A", (enumDefaults[1] as EnumDefaultSchemaTransform).old)
}
@Test
@ -299,8 +302,8 @@ class EnumEvolvabilityTests {
assertEquals("X", (serialisedSchema[TransformTypes.Rename]!![0] as RenameSchemaTransform).to)
assertEquals(1, serialisedSchema[TransformTypes.EnumDefault]!!.size)
assertEquals("E", (serialisedSchema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).new)
assertEquals("X", (serialisedSchema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemeTransform).old)
assertEquals("E", (serialisedSchema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).new)
assertEquals("X", (serialisedSchema[TransformTypes.EnumDefault]!![0] as EnumDefaultSchemaTransform).old)
}
@CordaSerializationTransformEnumDefaults (
@ -402,6 +405,32 @@ class EnumEvolvabilityTests {
assertEquals (sb1.transformsSchema.types[AnnotatedEnumOnce::class.java.name],
sb2.transformsSchema.types[AnnotatedEnumOnce::class.java.name])
}
// @UnknownTransformAnnotation (10, 20, 30)
enum class WithUnknownTest {
A, B, C, D
}
data class WrapsUnknown(val unknown: WithUnknownTest)
// To regenerate the types for this test uncomment the UnknownTransformAnnotation from
// TransformTypes.kt and SupportedTransforms.kt
@Test
fun testUnknownTransform() {
val resource = "EnumEvolvabilityTests.testUnknownTransform"
val sf = testDefaultFactory()
//File(URI("$localPath/$resource")).writeBytes(
// SerializationOutput(sf).serialize(WrapsUnknown(WithUnknownTest.D)).bytes)
val path = EvolvabilityTests::class.java.getResource(resource)
val sb1 = File(path.toURI()).readBytes()
val envelope = DeserializationInput(sf).deserializeAndReturnEnvelope(SerializedBytes<WrapsUnknown>(sb1)).envelope
assertTrue(envelope.transformsSchema.types.containsKey(WithUnknownTest::class.java.name))
assertTrue(envelope.transformsSchema.types[WithUnknownTest::class.java.name]!!.containsKey(TransformTypes.Unknown))
}
}

View File

@ -5,36 +5,40 @@ import net.corda.core.serialization.SerializedBytes
import org.junit.Test
import java.io.File
import java.io.NotSerializableException
import java.net.URI
import kotlin.test.assertEquals
// To regenerate any of the binary test files do the following
//
// 0. set localPath accordingly
// 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 {
// When regenerating the test files this needs to be set to the file system location of the resource files
var localPath = "file:///<path>/<to>/<toplevel of>/corda/node-api/src/test/resources/net/corda/nodeapi/internal/serialization/amqp"
@Test
fun simpleOrderSwapSameType() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.simpleOrderSwapSameType")
val f = File(path.toURI())
val resource= "EvolvabilityTests.simpleOrderSwapSameType"
val A = 1
val B = 2
// Original version of the class for the serialised version of this class
//
// data class C (val a: Int, val b: Int)
// val sc = SerializationOutput(sf).serialize(C(A, B))
// f.writeBytes(sc.bytes)
// println (path)
// File(URI("$localPath/$resource")).writeBytes(sc.bytes)
// new version of the class, in this case the order of the parameters has been swapped
data class C(val b: Int, val a: Int)
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes<C>(sc2))
@ -45,21 +49,20 @@ class EvolvabilityTests {
@Test
fun simpleOrderSwapDifferentType() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.simpleOrderSwapDifferentType")
val f = File(path.toURI())
val A = 1
val B = "two"
val resource = "EvolvabilityTests.simpleOrderSwapDifferentType"
// Original version of the class as it was serialised
//
// data class C (val a: Int, val b: String)
// val sc = SerializationOutput(sf).serialize(C(A, B))
// f.writeBytes(sc.bytes)
// println (path)
// File(URI("$localPath/$resource")).writeBytes(sc.bytes)
// new version of the class, in this case the order of the parameters has been swapped
data class C(val b: String, val a: Int)
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes<C>(sc2))
@ -70,18 +73,18 @@ class EvolvabilityTests {
@Test
fun addAdditionalParamNotMandatory() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.addAdditionalParamNotMandatory")
val f = File(path.toURI())
val A = 1
val resource = "EvolvabilityTests.addAdditionalParamNotMandatory"
// Original version of the class as it was serialised
//
// data class C(val a: Int)
// val sc = SerializationOutput(sf).serialize(C(A))
// f.writeBytes(sc.bytes)
// println ("Path = $path")
// File(URI("$localPath/$resource")).writeBytes(sc.bytes)
data class C(val a: Int, val b: Int?)
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedC = DeserializationInput(sf).deserialize(SerializedBytes<C>(sc2))
@ -119,22 +122,21 @@ class EvolvabilityTests {
@Test
fun removeParameters() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.removeParameters")
val f = File(path.toURI())
val resource = "EvolvabilityTests.removeParameters"
val A = 1
val B = "two"
val C = "three"
val D = 4
// Original version of the class as it was serialised
//
// data class CC(val a: Int, val b: String, val c: String, val d: Int)
// val scc = SerializationOutput(sf).serialize(CC(A, B, C, D))
// f.writeBytes(scc.bytes)
// println ("Path = $path")
// File(URI("$localPath/$resource")).writeBytes(scc.bytes)
data class CC(val b: String, val d: Int)
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.removeParameters")
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes<CC>(sc2))
@ -146,23 +148,23 @@ class EvolvabilityTests {
@Test
fun addAndRemoveParameters() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.addAndRemoveParameters")
val f = File(path.toURI())
val A = 1
val B = "two"
val C = "three"
val D = 4
val E = null
val resource = "EvolvabilityTests.addAndRemoveParameters"
// Original version of the class as it was serialised
//
// data class CC(val a: Int, val b: String, val c: String, val d: Int)
// val scc = SerializationOutput(sf).serialize(CC(A, B, C, D))
// f.writeBytes(scc.bytes)
// println ("Path = $path")
// File(URI("$localPath/$resource")).writeBytes(scc.bytes)
data class CC(val a: Int, val e: Boolean?, val d: Int)
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes<CC>(sc2))
@ -174,16 +176,13 @@ class EvolvabilityTests {
@Test
fun addMandatoryFieldWithAltConstructor() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.addMandatoryFieldWithAltConstructor")
val f = File(path.toURI())
val A = 1
val resource = "EvolvabilityTests.addMandatoryFieldWithAltConstructor"
// Original version of the class as it was serialised
//
// data class CC(val a: Int)
// val scc = SerializationOutput(sf).serialize(CC(A))
// f.writeBytes(scc.bytes)
// println ("Path = $path")
// File(URI("$localPath/$resource")).writeBytes(scc.bytes)
@Suppress("UNUSED")
data class CC(val a: Int, val b: String) {
@ -191,6 +190,8 @@ class EvolvabilityTests {
constructor (a: Int) : this(a, "hello")
}
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes<CC>(sc2))
@ -228,19 +229,15 @@ class EvolvabilityTests {
@Test
fun addMandatoryFieldWithAltReorderedConstructor() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource(
"EvolvabilityTests.addMandatoryFieldWithAltReorderedConstructor")
val f = File(path.toURI())
val resource = "EvolvabilityTests.addMandatoryFieldWithAltReorderedConstructor"
val A = 1
val B = 100
val C = "This is not a banana"
// Original version of the class as it was serialised
//
// data class CC(val a: Int, val b: Int, val c: String)
// val scc = SerializationOutput(sf).serialize(CC(A, B, C))
// f.writeBytes(scc.bytes)
// println ("Path = $path")
// File(URI("$localPath/$resource")).writeBytes(scc.bytes)
@Suppress("UNUSED")
data class CC(val a: Int, val b: Int, val c: String, val d: String) {
@ -250,6 +247,8 @@ class EvolvabilityTests {
constructor (c: String, a: Int, b: Int) : this(a, b, c, "wibble")
}
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes<CC>(sc2))
@ -262,20 +261,15 @@ class EvolvabilityTests {
@Test
fun addMandatoryFieldWithAltReorderedConstructorAndRemoval() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource(
"EvolvabilityTests.addMandatoryFieldWithAltReorderedConstructorAndRemoval")
val f = File(path.toURI())
val resource = "EvolvabilityTests.addMandatoryFieldWithAltReorderedConstructorAndRemoval"
val A = 1
@Suppress("UNUSED_VARIABLE")
val B = 100
val C = "This is not a banana"
// Original version of the class as it was serialised
//
// data class CC(val a: Int, val b: Int, val c: String)
// val scc = SerializationOutput(sf).serialize(CC(A, B, C))
// f.writeBytes(scc.bytes)
// println ("Path = $path")
// File(URI("$localPath/$resource")).writeBytes(SerializationOutput(sf).serialize(CC(A, B, C)).bytes)
// b is removed, d is added
data class CC(val a: Int, val c: String, val d: String) {
@ -286,6 +280,8 @@ class EvolvabilityTests {
constructor (c: String, a: Int) : this(a, c, "wibble")
}
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val deserializedCC = DeserializationInput(sf).deserialize(SerializedBytes<CC>(sc2))
@ -297,9 +293,9 @@ class EvolvabilityTests {
@Test
fun multiVersion() {
val sf = testDefaultFactory()
val path1 = EvolvabilityTests::class.java.getResource("EvolvabilityTests.multiVersion.1")
val path2 = EvolvabilityTests::class.java.getResource("EvolvabilityTests.multiVersion.2")
val path3 = EvolvabilityTests::class.java.getResource("EvolvabilityTests.multiVersion.3")
val resource1 = "EvolvabilityTests.multiVersion.1"
val resource2 = "EvolvabilityTests.multiVersion.2"
val resource3 = "EvolvabilityTests.multiVersion.3"
val a = 100
val b = 200
@ -310,24 +306,15 @@ class EvolvabilityTests {
//
// Version 1:
// data class C (val a: Int, val b: Int)
//
// val scc = SerializationOutput(sf).serialize(C(a, b))
// File(path1.toURI()).writeBytes(scc.bytes)
// println ("Path = $path1")
// File(URI("$localPath/$resource1")).writeBytes(SerializationOutput(sf).serialize(C(a, b)).bytes)
//
// Version 2 - add param c
// data class C (val c: Int, val b: Int, val a: Int)
//
// val scc = SerializationOutput(sf).serialize(C(c, b, a))
// File(path2.toURI()).writeBytes(scc.bytes)
// println ("Path = $path2")
// File(URI("$localPath/$resource2")).writeBytes(SerializationOutput(sf).serialize(C(c, b, a)).bytes)
//
// Version 3 - add param d
// data class C (val b: Int, val c: Int, val d: Int, val a: Int)
//
// val scc = SerializationOutput(sf).serialize(C(b, c, d, a))
// File(path3.toURI()).writeBytes(scc.bytes)
// println ("Path = $path3")
// File(URI("$localPath/$resource3")).writeBytes(SerializationOutput(sf).serialize(C(b, c, d, a)).bytes)
@Suppress("UNUSED")
data class C(val e: Int, val c: Int, val b: Int, val a: Int, val d: Int) {
@ -341,6 +328,10 @@ class EvolvabilityTests {
constructor (a: Int, b: Int, c: Int, d: Int) : this(-1, c, b, a, d)
}
val path1 = EvolvabilityTests::class.java.getResource(resource1)
val path2 = EvolvabilityTests::class.java.getResource(resource2)
val path3 = EvolvabilityTests::class.java.getResource(resource3)
val sb1 = File(path1.toURI()).readBytes()
val db1 = DeserializationInput(sf).deserialize(SerializedBytes<C>(sb1))
@ -372,24 +363,21 @@ class EvolvabilityTests {
@Test
fun changeSubType() {
val sf = testDefaultFactory()
val path = EvolvabilityTests::class.java.getResource("EvolvabilityTests.changeSubType")
val f = File(path.toURI())
val resource = "EvolvabilityTests.changeSubType"
val oa = 100
val ia = 200
// Original version of the class as it was serialised
//
// data class Inner (val a: Int)
// data class Outer (val a: Int, val b: Inner)
// val scc = SerializationOutput(sf).serialize(Outer(oa, Inner (ia)))
// f.writeBytes(scc.bytes)
// println ("Path = $path")
// File(URI("$localPath/$resource")).writeBytes(SerializationOutput(sf).serialize(Outer(oa, Inner (ia))).bytes)
// Add a parameter to inner but keep outer unchanged
data class Inner(val a: Int, val b: String?)
data class Outer(val a: Int, val b: Inner)
val path = EvolvabilityTests::class.java.getResource(resource)
val f = File(path.toURI())
val sc2 = f.readBytes()
val outer = DeserializationInput(sf).deserialize(SerializedBytes<Outer>(sc2))
@ -401,9 +389,10 @@ class EvolvabilityTests {
@Test
fun multiVersionWithRemoval() {
val sf = testDefaultFactory()
val path1 = EvolvabilityTests::class.java.getResource("EvolvabilityTests.multiVersionWithRemoval.1")
val path2 = EvolvabilityTests::class.java.getResource("EvolvabilityTests.multiVersionWithRemoval.2")
val path3 = EvolvabilityTests::class.java.getResource("EvolvabilityTests.multiVersionWithRemoval.3")
val resource1 = "EvolvabilityTests.multiVersionWithRemoval.1"
val resource2 = "EvolvabilityTests.multiVersionWithRemoval.2"
val resource3 = "EvolvabilityTests.multiVersionWithRemoval.3"
@Suppress("UNUSED_VARIABLE")
val a = 100
@ -417,24 +406,15 @@ class EvolvabilityTests {
//
// Version 1:
// data class C (val a: Int, val b: Int, val c: Int)
// File(URI("$localPath/$resource1")).writeBytes(SerializationOutput(sf).serialize(C(a, b, c)).bytes)
//
// val scc = SerializationOutput(sf).serialize(C(a, b, c))
// File(path1.toURI()).writeBytes(scc.bytes)
// println ("Path = $path1")
//
// Version 2 - add param c
// Version 2 - remove property a, add property e
// data class C (val b: Int, val c: Int, val d: Int, val e: Int)
//
// val scc = SerializationOutput(sf).serialize(C(b, c, d, e))
// File(path2.toURI()).writeBytes(scc.bytes)
// println ("Path = $path2")
// File(URI("$localPath/$resource2")).writeBytes(SerializationOutput(sf).serialize(C(b, c, d, e)).bytes)
//
// Version 3 - add param d
// data class C (val b: Int, val c: Int, val d: Int, val e: Int, val f: Int)
//
// val scc = SerializationOutput(sf).serialize(C(b, c, d, e, f))
// File(path3.toURI()).writeBytes(scc.bytes)
// println ("Path = $path3")
// File(URI("$localPath/$resource3")).writeBytes(SerializationOutput(sf).serialize(C(b, c, d, e, f)).bytes)
@Suppress("UNUSED")
data class C(val b: Int, val c: Int, val d: Int, val e: Int, val f: Int, val g: Int) {
@ -451,6 +431,10 @@ class EvolvabilityTests {
constructor (b: Int, c: Int, d: Int, e: Int, f: Int) : this(b, c, d, e, f, -1)
}
val path1 = EvolvabilityTests::class.java.getResource(resource1)
val path2 = EvolvabilityTests::class.java.getResource(resource2)
val path3 = EvolvabilityTests::class.java.getResource(resource3)
val sb1 = File(path1.toURI()).readBytes()
val db1 = DeserializationInput(sf).deserialize(SerializedBytes<C>(sb1))