Review comments

* Move all alterations on the amqp schema object out of the actual
  amqp/Schema file and have them live in the carpenter as extension
  functions
* Move carpenter exceptions to their own file
* Rename the schema name corrupter to the name mangler
* reduce whitespace
* alter comment style
This commit is contained in:
Katelyn Baker 2017-07-12 10:37:23 +01:00
parent 5ab26dd275
commit 86902e6356
11 changed files with 283 additions and 417 deletions

View File

@ -15,11 +15,8 @@ import java.lang.reflect.Type
import java.lang.reflect.TypeVariable
import java.util.*
import net.corda.core.serialization.carpenter.CarpenterSchemas
import net.corda.core.serialization.carpenter.Schema as CarpenterSchema
import net.corda.core.serialization.carpenter.Field as CarpenterField
import net.corda.core.serialization.carpenter.CarpenterSchemaFactory
import net.corda.core.serialization.carpenter.FieldFactory
// TODO: get an assigned number as per AMQP spec
val DESCRIPTOR_TOP_32BITS: Long = 0xc0da0000
@ -29,24 +26,6 @@ val DESCRIPTOR_DOMAIN: String = "net.corda"
// "corda" + majorVersionByte + minorVersionMSB + minorVersionLSB
val AmqpHeaderV1_0: OpaqueBytes = OpaqueBytes("corda\u0001\u0000\u0000".toByteArray())
private fun List<ClassLoader>.exists (clazz: String) =
this.find { try { it.loadClass(clazz); true } catch (e: ClassNotFoundException) { false } } != null
private fun List<ClassLoader>.loadIfExists (clazz: String) : Class<*> {
this.forEach {
try {
return it.loadClass(clazz)
} catch (e: ClassNotFoundException) {
return@forEach
}
}
throw ClassNotFoundException(clazz)
}
class UncarpentableException (name: String, field: String, type: String) :
Throwable ("Class $name is loadable yet contains field $field of unknown type $type")
/**
* This class wraps all serialized data, so that the schema can be carried along with it. We will provide various internal utilities
* to decompose and recompose with/without schema etc so that e.g. we can store objects with a (relationally) normalised out schema to
@ -111,18 +90,6 @@ data class Schema(val types: List<TypeNotation>) : DescribedType {
override fun getDescribed(): Any = listOf(types)
override fun toString(): String = types.joinToString("\n")
fun carpenterSchema(loaders : List<ClassLoader> = listOf<ClassLoader>(ClassLoader.getSystemClassLoader()))
: CarpenterSchemas
{
val rtn = CarpenterSchemas.newInstance()
types.filterIsInstance<CompositeType>().forEach {
it.carpenterSchema(classLoaders = loaders, carpenterSchemas = rtn)
}
return rtn
}
}
data class Descriptor(val name: String?, val code: UnsignedLong? = null) : DescribedType {
@ -205,29 +172,6 @@ data class Field(val name: String, val type: String, val requires: List<String>,
return sb.toString()
}
fun getTypeAsClass(
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())
) = when (type) {
"int" -> Int::class.javaPrimitiveType!!
"string" -> String::class.java
"short" -> Short::class.javaPrimitiveType!!
"long" -> Long::class.javaPrimitiveType!!
"char" -> Char::class.javaPrimitiveType!!
"boolean" -> Boolean::class.javaPrimitiveType!!
"double" -> Double::class.javaPrimitiveType!!
"float" -> Float::class.javaPrimitiveType!!
"*" -> classLoaders.loadIfExists(requires[0])
else -> classLoaders.loadIfExists(type)
}
fun validateType(
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())
) = when (type) {
"int", "string", "short", "long", "char", "boolean", "double", "float" -> true
"*" -> classLoaders.exists(requires[0])
else -> classLoaders.exists (type)
}
fun typeAsString() = if (type =="*") requires[0] else type
}
@ -294,85 +238,6 @@ data class CompositeType(override val name: String, override val label: String?,
sb.append("</type>")
return sb.toString()
}
/**
* if we can load the class then we MUST know about all of it's composite elements
*/
private fun validateKnown (
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader()))
{
fields.forEach {
if (!it.validateType(classLoaders)) throw UncarpentableException (name, it.name, it.type)
}
}
/**
* based upon this AMQP schema either
* a) add the corespending carpenter schema to the [carpenterSchemas] param
* 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 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 carpenterSchema(
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader()),
carpenterSchemas : CarpenterSchemas,
force : Boolean = false)
{
/* first question, do we know about this type or not */
if (classLoaders.exists(name)) {
validateKnown(classLoaders)
if (!force) return
}
val providesList = mutableListOf<Class<*>>()
var isInterface = false
var isCreatable = true
provides.forEach {
if (name == it) {
isInterface = true
return@forEach
}
try {
providesList.add (classLoaders.loadIfExists(it))
}
catch (e: ClassNotFoundException) {
carpenterSchemas.addDepPair(this, name, it)
isCreatable = false
}
}
val m : MutableMap<String, CarpenterField> = mutableMapOf()
fields.forEach {
try {
m[it.name] = FieldFactory.newInstance(it.mandatory, it.name, it.getTypeAsClass(classLoaders))
}
catch (e: ClassNotFoundException) {
carpenterSchemas.addDepPair(this, name, it.typeAsString())
isCreatable = false
}
}
if (isCreatable) {
carpenterSchemas.carpenterSchemas.add (CarpenterSchemaFactory.newInstance(
name = name,
fields = m,
interfaces = providesList,
isInterface = isInterface))
}
}
}
data class RestrictedType(override val name: String, override val label: String?, override val provides: List<String>, val source: String, override val descriptor: Descriptor, val choices: List<Choice>) : TypeNotation() {

View File

@ -0,0 +1,127 @@
package net.corda.core.serialization.carpenter
import net.corda.core.serialization.amqp.Schema as AMQPSchema
import net.corda.core.serialization.amqp.Field as AMQPField
import net.corda.core.serialization.amqp.CompositeType
fun AMQPSchema.carpenterSchema(
loaders : List<ClassLoader> = listOf<ClassLoader>(ClassLoader.getSystemClassLoader()))
: CarpenterSchemas {
val rtn = CarpenterSchemas.newInstance()
types.filterIsInstance<CompositeType>().forEach {
it.carpenterSchema(classLoaders = loaders, carpenterSchemas = rtn)
}
return rtn
}
/**
* if we can load the class then we MUST know about all of it's composite elements
*/
private fun CompositeType.validateKnown (
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())){
fields.forEach {
if (!it.validateType(classLoaders)) throw UncarpentableException (name, it.name, it.type)
}
}
/**
* based upon this AMQP schema either
* a) add the corresponding carpenter schema to the [carpenterSchemas] param
* 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 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)) {
validateKnown(classLoaders)
if (!force) return
}
val providesList = mutableListOf<Class<*>>()
var isInterface = false
var isCreatable = true
provides.forEach {
if (name == it) {
isInterface = true
return@forEach
}
try {
providesList.add (classLoaders.loadIfExists(it))
}
catch (e: ClassNotFoundException) {
carpenterSchemas.addDepPair(this, name, it)
isCreatable = false
}
}
val m : MutableMap<String, Field> = mutableMapOf()
fields.forEach {
try {
m[it.name] = FieldFactory.newInstance(it.mandatory, it.name, it.getTypeAsClass(classLoaders))
}
catch (e: ClassNotFoundException) {
carpenterSchemas.addDepPair(this, name, it.typeAsString())
isCreatable = false
}
}
if (isCreatable) {
carpenterSchemas.carpenterSchemas.add (CarpenterSchemaFactory.newInstance(
name = name,
fields = m,
interfaces = providesList,
isInterface = isInterface))
}
}
fun AMQPField.getTypeAsClass(
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())
) = when (type) {
"int" -> Int::class.javaPrimitiveType!!
"string" -> String::class.java
"short" -> Short::class.javaPrimitiveType!!
"long" -> Long::class.javaPrimitiveType!!
"char" -> Char::class.javaPrimitiveType!!
"boolean" -> Boolean::class.javaPrimitiveType!!
"double" -> Double::class.javaPrimitiveType!!
"float" -> Float::class.javaPrimitiveType!!
"*" -> classLoaders.loadIfExists(requires[0])
else -> classLoaders.loadIfExists(type)
}
fun AMQPField.validateType(
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())
) = when (type) {
"int", "string", "short", "long", "char", "boolean", "double", "float" -> true
"*" -> classLoaders.exists(requires[0])
else -> classLoaders.exists (type)
}
private fun List<ClassLoader>.exists (clazz: String) =
this.find { try { it.loadClass(clazz); true } catch (e: ClassNotFoundException) { false } } != null
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

@ -9,8 +9,6 @@ import java.lang.Character.isJavaIdentifierStart
import java.util.*
/**********************************************************************************************************************/
/**
* Any object that implements this interface is expected to expose its own fields via the [get] method, exactly
* as if `this.class.getMethod("get" + name.capitalize()).invoke(this)` had been called. It is intended as a more
@ -20,14 +18,10 @@ interface SimpleFieldAccess {
operator fun get(name: String): Any?
}
/**********************************************************************************************************************/
class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoader) {
fun load(name: String, bytes: ByteArray) = defineClass(name, bytes, 0, bytes.size)
}
/**********************************************************************************************************************/
/**
* A class carpenter generates JVM bytecodes for a class given a schema and then loads it into a sub-classloader.
* The generated classes have getters, a toString method and implement a simple property access interface. The
@ -91,7 +85,8 @@ class ClassCarpenter {
* Generate bytecode for the given schema and load into the JVM. The returned class object can be used to
* construct instances of the generated class.
*
* @throws DuplicateNameException if the schema's name is already taken in this namespace (you can create a new ClassCarpenter if you're OK with ambiguous names)
* @throws DuplicateNameException if the schema's name is already taken in this namespace (you can create a
* new ClassCarpenter if you're OK with ambiguous names)
*/
fun build(schema: Schema): Class<*> {
validateSchema(schema)
@ -257,9 +252,7 @@ class ClassCarpenter {
visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
} else {
var slot = 1
for (fieldType in superclassFields.values)
slot += load(slot, fieldType)
//val superDesc = schema.superclass.descriptorsIncludingSuperclasses().values.joinToString("")
superclassFields.values.forEach { slot += load(slot, it) }
val superDesc = sc.descriptorsIncludingSuperclasses().values.joinToString("")
visitMethodInsn(INVOKESPECIAL, sc.name.jvm, "<init>", "($superDesc)V", false)
}

View File

@ -1,9 +1,11 @@
package net.corda.core.serialization.carpenter
class DuplicateNameException : RuntimeException (
"An attempt was made to register two classes with the same name within the same ClassCarpenter namespace.")
class InterfaceMismatchException(msg: String) : RuntimeException(msg)
class NullablePrimitiveException(msg: String) : RuntimeException(msg)
class UncarpentableException (name: String, field: String, type: String) :
Exception ("Class $name is loadable yet contains field $field of unknown type $type")

View File

@ -3,8 +3,6 @@ package net.corda.core.serialization.carpenter
import net.corda.core.serialization.amqp.CompositeType
import net.corda.core.serialization.amqp.TypeNotation
/**********************************************************************************************************************/
/**
* Generated from an AMQP schema this class represents the classes unknown to the deserialiser and that thusly
* require carpenting up in bytecode form. This is a multi step process as carpenting one object may be depedent
@ -27,8 +25,7 @@ import net.corda.core.serialization.amqp.TypeNotation
data class CarpenterSchemas (
val carpenterSchemas : MutableList<Schema>,
val dependencies : MutableMap<String, Pair<TypeNotation, MutableList<String>>>,
val dependsOn : MutableMap<String, MutableList<String>>)
{
val dependsOn : MutableMap<String, MutableList<String>>) {
companion object CarpenterSchemaConstructor {
fun newInstance(): CarpenterSchemas {
return CarpenterSchemas(
@ -47,8 +44,6 @@ data class CarpenterSchemas (
get() = carpenterSchemas.size
}
/**********************************************************************************************************************/
/**
* Take a dependency tree of [CarpenterSchemas] and reduce it to zero by carpenting those classes that
* require it. As classes are carpented check for depdency resolution, if now free generate a [Schema] for
@ -65,15 +60,15 @@ abstract class MetaCarpenterBase (val schemas : CarpenterSchemas) {
fun step (newObject : Schema) {
objects[newObject.name] = cc.build (newObject)
/* go over the list of everything that had a dependency on the newly
carpented class existing and remove it from their dependency list, If that
list is now empty we have no impediment to carpenting that class up */
// go over the list of everything that had a dependency on the newly
// carpented class existing and remove it from their dependency list, If that
// list is now empty we have no impediment to carpenting that class up
schemas.dependsOn.remove(newObject.name)?.forEach { dependent ->
assert (newObject.name in schemas.dependencies[dependent]!!.second)
schemas.dependencies[dependent]?.second?.remove(newObject.name)
/* we're out of blockers so we can now create the type */
// 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> (
@ -87,8 +82,6 @@ abstract class MetaCarpenterBase (val schemas : CarpenterSchemas) {
abstract fun build()
}
/**********************************************************************************************************************/
class MetaCarpenter (schemas : CarpenterSchemas) : MetaCarpenterBase (schemas) {
override fun build() {
while (schemas.carpenterSchemas.isNotEmpty()) {
@ -98,8 +91,6 @@ class MetaCarpenter (schemas : CarpenterSchemas) : MetaCarpenterBase (schemas) {
}
}
/**********************************************************************************************************************/
class TestMetaCarpenter (schemas : CarpenterSchemas) : MetaCarpenterBase (schemas) {
override fun build() {
if (schemas.carpenterSchemas.isEmpty()) return
@ -107,4 +98,3 @@ class TestMetaCarpenter (schemas : CarpenterSchemas) : MetaCarpenterBase (schema
}
}
/**********************************************************************************************************************/

View File

@ -264,7 +264,6 @@ class ClassCarpenterTest {
mapOf("a" to NonNullableField (Int::class.java)))
val clazz = cc.build(schema)
val a : Int? = null
clazz.constructors[0].newInstance(a)
}
@ -364,7 +363,6 @@ class ClassCarpenterTest {
val clazz = cc.build(schema)
val i = clazz.constructors[0].newInstance(arrayOf(1, 2, 3)) as SimpleFieldAccess
val arr = clazz.getMethod("getA").invoke(i)
assertEquals(1, (arr as Array<Int>)[0])
@ -384,14 +382,12 @@ class ClassCarpenterTest {
"c" to Int::class.java).mapValues { NonNullableField(it.value) })
val clazz = cc.build(schema)
val i = clazz.constructors[0].newInstance(2, intArrayOf(4, 8), 16) as SimpleFieldAccess
assertEquals(2, clazz.getMethod("getA").invoke(i))
assertEquals(4, (clazz.getMethod("getB").invoke(i) as IntArray)[0])
assertEquals(8, (clazz.getMethod("getB").invoke(i) as IntArray)[1])
assertEquals(16, clazz.getMethod("getC").invoke(i))
assertEquals("$className{a=2, b=[4, 8], c=16}", i.toString())
}
@ -414,7 +410,6 @@ class ClassCarpenterTest {
assertEquals(4, (clazz.getMethod("getC").invoke(i) as IntArray)[0])
assertEquals(5, (clazz.getMethod("getC").invoke(i) as IntArray)[1])
assertEquals(6, (clazz.getMethod("getC").invoke(i) as IntArray)[2])
assertEquals("$className{a=[1, 2], b=3, c=[4, 5, 6]}", i.toString())
}
@ -454,7 +449,6 @@ class ClassCarpenterTest {
"and on the side",
arrayOf("some pickles", "some fries"))
val arr1 = clazz.getMethod("getA").invoke(i) as Array<String>
val arr2 = clazz.getMethod("getC").invoke(i) as Array<String>
@ -477,16 +471,12 @@ class ClassCarpenterTest {
val clazz = cc.build(schema)
assertEquals (2, clazz.declaredFields.size)
assertEquals (1, clazz.getDeclaredField("a").annotations.size)
assertEquals (javax.annotation.Nullable::class.java, clazz.getDeclaredField("a").annotations[0].annotationClass.java)
assertEquals (1, clazz.getDeclaredField("b").annotations.size)
assertEquals (javax.annotation.Nonnull::class.java, clazz.getDeclaredField("b").annotations[0].annotationClass.java)
assertEquals (1, clazz.getMethod("getA").annotations.size)
assertEquals (javax.annotation.Nullable::class.java, clazz.getMethod("getA").annotations[0].annotationClass.java)
assertEquals (1, clazz.getMethod("getB").annotations.size)
assertEquals (javax.annotation.Nonnull::class.java, clazz.getMethod("getB").annotations[0].annotationClass.java)
}
@ -503,5 +493,4 @@ class ClassCarpenterTest {
assertNotEquals(null, descriptors.find { it.name == "a" })
assertNotEquals(null, descriptors.find { it.name == "class" })
}
}

View File

@ -7,32 +7,25 @@ import net.corda.core.serialization.amqp.TypeNotation
import net.corda.core.serialization.amqp.SerializerFactory
import net.corda.core.serialization.amqp.SerializationOutput
/**********************************************************************************************************************/
fun mangleName(name: String) = "${name}__carpenter"
fun corruptName(name: String) = "${name}__carpenter"
/**********************************************************************************************************************/
/* given a list of class names work through the amqp envelope schema and alter any that
match in the fashion defined above */
fun Schema.corruptName(names: List<String>): Schema {
/**
* given a list of class names work through the amqp envelope schema and alter any that
* match in the fashion defined above
*/
fun Schema.mangleName(names: List<String>): Schema {
val newTypes: MutableList<TypeNotation> = mutableListOf()
for (type in types) {
val newName = if (type.name in names) corruptName(type.name) else type.name
val newProvides = type.provides.map {
it ->
if (it in names) corruptName(it) else it
}
val newName = if (type.name in names) mangleName(type.name) else type.name
val newProvides = type.provides.map { it -> if (it in names) mangleName(it) else it }
val newFields = mutableListOf<Field>()
(type as CompositeType).fields.forEach {
val fieldType = if (it.type in names) corruptName(it.type) else it.type
val requires = if (it.requires.isNotEmpty() && (it.requires[0] in names))
listOf(corruptName(it.requires[0])) else it.requires
val fieldType = if (it.type in names) mangleName(it.type) else it.type
val requires =
if (it.requires.isNotEmpty() && (it.requires[0] in names)) listOf(mangleName(it.requires[0]))
else it.requires
newFields.add(it.copy(type = fieldType, requires = requires))
}
@ -43,8 +36,6 @@ fun Schema.corruptName(names: List<String>): Schema {
return Schema(types = newTypes)
}
/**********************************************************************************************************************/
open class AmqpCarpenterBase {
var factory = SerializerFactory()

View File

@ -14,11 +14,7 @@ interface I_ {
val a: Int
}
/*
* Where a class has a member that is also a composite type or interface
*/
class CompositeMembers : AmqpCarpenterBase() {
@Test
fun bothKnown() {
val testA = 10
@ -31,7 +27,6 @@ class CompositeMembers : AmqpCarpenterBase() {
data class B(val a: A, var b: Int)
val b = B(A(testA), testB)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
assert(obj.obj is B)
@ -57,10 +52,8 @@ class CompositeMembers : AmqpCarpenterBase() {
assert(amqpSchemaA != null)
assert(amqpSchemaB != null)
/*
* Just ensure the amqp schema matches what we want before we go messing
* around with the internals
*/
// Just ensure the amqp schema matches what we want before we go messing
// around with the internals
assertEquals(1, amqpSchemaA?.fields?.size)
assertEquals("a", amqpSchemaA!!.fields[0].name)
assertEquals("int", amqpSchemaA.fields[0].type)
@ -73,15 +66,15 @@ class CompositeMembers : AmqpCarpenterBase() {
val metaSchema = obj.envelope.schema.carpenterSchema()
/* if we know all the classes there is nothing to really achieve here */
// if we know all the classes there is nothing to really achieve here
assert(metaSchema.carpenterSchemas.isEmpty())
assert(metaSchema.dependsOn.isEmpty())
assert(metaSchema.dependencies.isEmpty())
}
/* you cannot have an element of a composite class we know about
that is unknown as that should be impossible. If we have the containing
class in the class path then we must have all of it's constituent elements */
// you cannot have an element of a composite class we know about
// that is unknown as that should be impossible. If we have the containing
// class in the class path then we must have all of it's constituent elements
@Test(expected = UncarpentableException::class)
fun nestedIsUnknown() {
val testA = 10
@ -96,7 +89,7 @@ class CompositeMembers : AmqpCarpenterBase() {
val b = B(A(testA), testB)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
val amqpSchema = obj.envelope.schema.corruptName(listOf (classTestName ("A")))
val amqpSchema = obj.envelope.schema.mangleName(listOf (classTestName ("A")))
assert(obj.obj is B)
@ -115,13 +108,11 @@ class CompositeMembers : AmqpCarpenterBase() {
data class B(val a: A, var b: Int)
val b = B(A(testA), testB)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
assert(obj.obj is B)
val amqpSchema = obj.envelope.schema.corruptName(listOf(classTestName("B")))
val amqpSchema = obj.envelope.schema.mangleName(listOf(classTestName("B")))
val carpenterSchema = amqpSchema.carpenterSchema()
assertEquals(1, carpenterSchema.size)
@ -130,11 +121,11 @@ class CompositeMembers : AmqpCarpenterBase() {
metaCarpenter.build()
assert(corruptName(classTestName("B")) in metaCarpenter.objects)
assert(mangleName(classTestName("B")) in metaCarpenter.objects)
}
@Test
fun BothUnkown() {
fun BothUnknown() {
val testA = 10
val testB = 20
@ -145,52 +136,50 @@ class CompositeMembers : AmqpCarpenterBase() {
data class B(val a: A, var b: Int)
val b = B(A(testA), testB)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
assert(obj.obj is B)
val amqpSchema = obj.envelope.schema.corruptName(listOf(classTestName("A"), classTestName("B")))
val amqpSchema = obj.envelope.schema.mangleName(listOf(classTestName("A"), classTestName("B")))
val carpenterSchema = amqpSchema.carpenterSchema()
/* 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 */
// 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
assertEquals(1, carpenterSchema.size)
assertEquals(corruptName(classTestName("A")), carpenterSchema.carpenterSchemas.first().name)
assertEquals(mangleName(classTestName("A")), carpenterSchema.carpenterSchemas.first().name)
assertEquals(1, carpenterSchema.dependencies.size)
assert(corruptName(classTestName("B")) in carpenterSchema.dependencies)
assert(mangleName(classTestName("B")) in carpenterSchema.dependencies)
assertEquals(1, carpenterSchema.dependsOn.size)
assert(corruptName(classTestName("A")) in carpenterSchema.dependsOn)
assert(mangleName(classTestName("A")) in carpenterSchema.dependsOn)
/* test meta carpenter lets us single step over the creation */
val metaCarpenter = TestMetaCarpenter(carpenterSchema)
/* we've built nothing so nothing should be there */
assertEquals(0, metaCarpenter.objects.size)
/* first iteration, carpent A, resolve deps and mark B as carpentable */
// first iteration, carpent A, resolve deps and mark B as carpentable
metaCarpenter.build()
/* one build iteration should have carpetned up A and worked out that B is now buildable
given it's depedencies have been satisfied */
assertTrue(corruptName(classTestName("A")) in metaCarpenter.objects)
assertFalse(corruptName(classTestName("B")) in metaCarpenter.objects)
// one build iteration should have carpetned up A and worked out that B is now buildable
// given it's depedencies have been satisfied
assertTrue(mangleName(classTestName("A")) in metaCarpenter.objects)
assertFalse(mangleName(classTestName("B")) in metaCarpenter.objects)
assertEquals(1, carpenterSchema.carpenterSchemas.size)
assertEquals(corruptName(classTestName("B")), carpenterSchema.carpenterSchemas.first().name)
assertEquals(mangleName(classTestName("B")), carpenterSchema.carpenterSchemas.first().name)
assertTrue(carpenterSchema.dependencies.isEmpty())
assertTrue(carpenterSchema.dependsOn.isEmpty())
/* second manual iteration, will carpent B */
// second manual iteration, will carpent B
metaCarpenter.build()
assert(corruptName(classTestName("A")) in metaCarpenter.objects)
assert(corruptName(classTestName("B")) in metaCarpenter.objects)
assert(mangleName(classTestName("A")) in metaCarpenter.objects)
assert(mangleName(classTestName("B")) in metaCarpenter.objects)
// and we must be finished
assertTrue(carpenterSchema.carpenterSchemas.isEmpty())
}
@Test(expected = UncarpentableException::class)
@Suppress("UNUSED")
fun nestedIsUnkownInherited() {
val testA = 10
val testB = 20
@ -206,18 +195,18 @@ class CompositeMembers : AmqpCarpenterBase() {
data class C(val b: B, var c: Int)
val c = C(B(testA, testB), testC)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(c))
assert(obj.obj is C)
val amqpSchema = obj.envelope.schema.corruptName(listOf(classTestName("A"), classTestName("B")))
val amqpSchema = obj.envelope.schema.mangleName(listOf(classTestName("A"), classTestName("B")))
amqpSchema.carpenterSchema()
}
@Test(expected = UncarpentableException::class)
fun nestedIsUnknownInheritedUnkown() {
@Suppress("UNUSED")
fun nestedIsUnknownInheritedUnknown() {
val testA = 10
val testB = 20
val testC = 30
@ -232,16 +221,16 @@ class CompositeMembers : AmqpCarpenterBase() {
data class C(val b: B, var c: Int)
val c = C(B(testA, testB), testC)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(c))
assert(obj.obj is C)
val amqpSchema = obj.envelope.schema.corruptName(listOf(classTestName("A"), classTestName("B")))
val amqpSchema = obj.envelope.schema.mangleName(listOf(classTestName("A"), classTestName("B")))
amqpSchema.carpenterSchema()
}
@Suppress("UNUSED")
@Test(expected = UncarpentableException::class)
fun parentsIsUnknownWithUnknownInheritedMember() {
val testA = 10
@ -258,18 +247,14 @@ class CompositeMembers : AmqpCarpenterBase() {
data class C(val b: B, var c: Int)
val c = C(B(testA, testB), testC)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(c))
assert(obj.obj is C)
val carpenterSchema = obj.envelope.schema.corruptName(listOf(classTestName("A"), classTestName("B")))
val carpenterSchema = obj.envelope.schema.mangleName(listOf(classTestName("A"), classTestName("B")))
TestMetaCarpenter(carpenterSchema.carpenterSchema())
}
/*
* TODO serializer doesn't support inheritnace at the moment, when it does this should work
@Test
@ -284,19 +269,17 @@ class CompositeMembers : AmqpCarpenterBase() {
class B(override val a: Int, val b: Int) : A (a)
val b = B(testA, testB)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
assert(obj.obj is B)
val carpenterSchema = obj.envelope.schema.corruptName(listOf(classTestName("A"), classTestName("B")))
val carpenterSchema = obj.envelope.schema.mangleName(listOf(classTestName("A"), classTestName("B")))
val metaCarpenter = TestMetaCarpenter(carpenterSchema.carpenterSchema())
assertEquals(1, metaCarpenter.schemas.carpenterSchemas.size)
assertEquals(corruptName(classTestName("B")), metaCarpenter.schemas.carpenterSchemas.first().name)
assertEquals(mangleName(classTestName("B")), metaCarpenter.schemas.carpenterSchemas.first().name)
assertEquals(1, metaCarpenter.schemas.dependencies.size)
assertTrue(corruptName(classTestName("A")) in metaCarpenter.schemas.dependencies)
assertTrue(mangleName(classTestName("A")) in metaCarpenter.schemas.dependencies)
}
*/
}

View File

@ -8,15 +8,11 @@ import net.corda.core.serialization.amqp.*
import org.junit.Test
import kotlin.test.*
/*******************************************************************************************************/
@CordaSerializable
interface J {
val j: Int
}
/*******************************************************************************************************/
@CordaSerializable
interface I {
val i: Int
@ -39,49 +35,36 @@ interface IIII {
val i: I
}
/*******************************************************************************************************/
class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun interfaceParent1() {
val testJ = 20
class A(override val j: Int) : J
val testJ = 20
val a = A(testJ)
assertEquals(testJ, a.j)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)
val serSchema = obj.envelope.schema
assertEquals(2, serSchema.types.size)
val l1 = serSchema.carpenterSchema()
/* since we're using an envelope generated by seilaising classes defined locally
it's extremely unlikely we'd need to carpent any classes */
// 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 corruptSchema = serSchema.corruptName(listOf(classTestName("A")))
val l2 = corruptSchema.carpenterSchema()
val mangleSchema = serSchema.mangleName(listOf(classTestName("A")))
val l2 = mangleSchema.carpenterSchema()
assertEquals(1, l2.size)
val aSchema = l2.carpenterSchemas.find { it.name == corruptName(classTestName("A")) }
val aSchema = l2.carpenterSchemas.find { it.name == mangleName(classTestName("A")) }
assertNotEquals(null, aSchema)
assertEquals(corruptName(classTestName("A")), aSchema!!.name)
assertEquals(mangleName(classTestName("A")), aSchema!!.name)
assertEquals(1, aSchema.interfaces.size)
assertEquals(net.corda.core.serialization.carpenter.J::class.java, aSchema.interfaces[0])
val aBuilder = ClassCarpenter().build(aSchema)
val objJ = aBuilder.constructors[0].newInstance(testJ)
val j = objJ as J
@ -89,14 +72,12 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
assertEquals(a.j, j.j)
}
@Test
fun interfaceParent2() {
val testJ = 20
val testJJ = 40
class A(override val j: Int, val jj: Int) : J
val testJ = 20
val testJJ = 40
val a = A(testJ, testJJ)
assertEquals(testJ, a.j)
@ -112,14 +93,12 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
val l1 = serSchema.carpenterSchema()
/* 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 corruptSchema = serSchema.corruptName(listOf(classTestName("A")))
val aName = corruptName(classTestName("A"))
val mangleSchema = serSchema.mangleName(listOf(classTestName("A")))
val aName = mangleName(classTestName("A"))
val l2 = corruptSchema.carpenterSchema()
val l2 = mangleSchema.carpenterSchema()
assertEquals(1, l2.size)
@ -160,48 +139,43 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
val l1 = serSchema.carpenterSchema()
/* since we're using an envelope generated by seilaising classes defined locally
it's extremely unlikely we'd need to carpent any classes */
// 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)
/* 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 corruptSchema = serSchema.corruptName(listOf(classTestName("A")))
val l2 = corruptSchema.carpenterSchema()
val aName = corruptName(classTestName("A"))
// 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.mangleName(listOf(classTestName("A")))
val l2 = mangleSchema.carpenterSchema()
val aName = mangleName(classTestName("A"))
assertEquals(1, l2.size)
val aSchema = l2.carpenterSchemas.find { it.name == aName }
assertNotEquals(null, aSchema)
assertEquals(aName, aSchema!!.name)
assertEquals(2, aSchema.interfaces.size)
assert(net.corda.core.serialization.carpenter.I::class.java in aSchema.interfaces)
assert(net.corda.core.serialization.carpenter.II::class.java in aSchema.interfaces)
val aBuilder = ClassCarpenter().build(aSchema)
val objA = aBuilder.constructors[0].newInstance(testI, testII)
val i = objA as I
val ii = objA as II
assertEquals(aBuilder.getMethod("getI").invoke(objA), testI)
assertEquals(aBuilder.getMethod("getIi").invoke(objA), testII)
assertEquals(a.i, i.i)
assertEquals(a.ii, ii.ii)
}
@Test
fun nestedInterfaces() {
val testI = 20
val testIII = 60
class A(override val i: Int, override val iii: Int) : III
val testI = 20
val testIII = 60
val a = A(testI, testIII)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
@ -213,34 +187,31 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
val l1 = serSchema.carpenterSchema()
/* since we're using an envelope generated by seilaising classes defined locally
it's extremely unlikely we'd need to carpent any classes */
// 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 corruptSchema = serSchema.corruptName(listOf(classTestName("A")))
val l2 = corruptSchema.carpenterSchema()
val aName = corruptName(classTestName("A"))
val mangleSchema = serSchema.mangleName(listOf(classTestName("A")))
val l2 = mangleSchema.carpenterSchema()
val aName = mangleName(classTestName("A"))
assertEquals(1, l2.size)
val aSchema = l2.carpenterSchemas.find { it.name == aName }
assertNotEquals(null, aSchema)
assertEquals(aName, aSchema!!.name)
assertEquals(2, aSchema.interfaces.size)
assert(net.corda.core.serialization.carpenter.I::class.java in aSchema.interfaces)
assert(net.corda.core.serialization.carpenter.III::class.java in aSchema.interfaces)
val aBuilder = ClassCarpenter().build(aSchema)
val objA = aBuilder.constructors[0].newInstance(testI, testIII)
val i = objA as I
val iii = objA as III
assertEquals(aBuilder.getMethod("getI").invoke(objA), testI)
assertEquals(aBuilder.getMethod("getIii").invoke(objA), testIII)
assertEquals(a.i, i.i)
assertEquals(a.i, iii.i)
assertEquals(a.iii, iii.iii)
@ -248,33 +219,30 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun memberInterface() {
val testI = 25
val testIIII = 50
class A(override val i: Int) : I
class B(override val i: I, override val iiii: Int) : IIII
val testI = 25
val testIIII = 50
val a = A(testI)
val b = B(a, testIIII)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
assert(obj.obj is B)
val serSchema = obj.envelope.schema
/*
* class A
* class A's interface (class I)
* class B
* class B's interface (class IIII)
*/
// Expected classes are
// * class A
// * class A's interface (class I)
// * class B
// * class B's interface (class IIII)
assertEquals(4, serSchema.types.size)
val corruptSchema = serSchema.corruptName(listOf(classTestName("A"), classTestName("B")))
val cSchema = corruptSchema.carpenterSchema()
val aName = corruptName(classTestName("A"))
val bName = corruptName(classTestName("B"))
val mangleSchema = serSchema.mangleName(listOf(classTestName("A"), classTestName("B")))
val cSchema = mangleSchema.carpenterSchema()
val aName = mangleName(classTestName("A"))
val bName = mangleName(classTestName("B"))
assertEquals(2, cSchema.size)
@ -286,102 +254,90 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
val cc = ClassCarpenter()
val cc2 = ClassCarpenter()
val bBuilder = cc.build(bCarpenterSchema!!)
bBuilder.constructors[0].newInstance(a, testIIII)
val aBuilder = cc.build(aCarpenterSchema!!)
val objA = aBuilder.constructors[0].newInstance(testI)
/* build a second B this time using our constructed instane of A and not the
local one we pre defined */
// build a second B this time using our constructed instance of A and not the
// local one we pre defined
bBuilder.constructors[0].newInstance(objA, testIIII)
/* whittle and instantiate a different A with a new class loader */
// whittle and instantiate a different A with a new class loader
val aBuilder2 = cc2.build(aCarpenterSchema)
val objA2 = aBuilder2.constructors[0].newInstance(testI)
bBuilder.constructors[0].newInstance(objA2, testIIII)
}
/* if we remove the neted interface we should get an error as it's impossible
to have a concrete class loaded without having access to all of it's elements */
// if we remove the nested interface we should get an error as it's impossible
// to have a concrete class loaded without having access to all of it's elements
@Test(expected = UncarpentableException::class)
fun memberInterface2() {
val testI = 25
val testIIII = 50
class A(override val i: Int) : I
class B(override val i: I, override val iiii: Int) : IIII
val testI = 25
val testIIII = 50
val a = A(testI)
val b = B(a, testIIII)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(b))
assert(obj.obj is B)
val serSchema = obj.envelope.schema
/*
* The classes we're expecting to find:
* class A
* class A's interface (class I)
* class B
* class B's interface (class IIII)
*/
// The classes we're expecting to find:
// * class A
// * class A's interface (class I)
// * class B
// * class B's interface (class IIII)
assertEquals(4, serSchema.types.size)
/* ignore the return as we expect this to throw */
serSchema.corruptName(listOf(
// ignore the return as we expect this to throw
serSchema.mangleName(listOf(
classTestName("A"), "${this.javaClass.`package`.name}.I")).carpenterSchema()
}
@Test
fun interfaceAndImplementation() {
val testI = 25
class A(override val i: Int) : I
val testI = 25
val a = A(testI)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)
val serSchema = obj.envelope.schema
/*
* The classes we're expecting to find:
* class A
* class A's interface (class I)
*/
// The classes we're expecting to find:
// * class A
// * class A's interface (class I)
assertEquals(2, serSchema.types.size)
val amqpSchema = serSchema.corruptName(listOf(classTestName("A"), "${this.javaClass.`package`.name}.I"))
val aName = corruptName(classTestName("A"))
val iName = corruptName("${this.javaClass.`package`.name}.I")
val amqpSchema = serSchema.mangleName(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()
/* 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 */
// 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
assertEquals(1, carpenterSchema.size)
assertNotEquals(null, carpenterSchema.carpenterSchemas.find { it.name == iName })
/* since we can't build A it should list I as a dependency*/
// since we can't build A it should list I as a dependency
assert(aName in carpenterSchema.dependencies)
assertEquals(1, carpenterSchema.dependencies[aName]!!.second.size)
assertEquals(iName, carpenterSchema.dependencies[aName]!!.second[0])
/* and conversly I should have A listed as a dependent */
// and conversly I should have A listed as a dependent
assert(iName in carpenterSchema.dependsOn)
assertEquals(1, carpenterSchema.dependsOn[iName]!!.size)
assertEquals(aName, carpenterSchema.dependsOn[iName]!![0])
val mc = MetaCarpenter(carpenterSchema)
mc.build()
assertEquals(0, mc.schemas.carpenterSchemas.size)
@ -396,29 +352,26 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun twoInterfacesAndImplementation() {
val testI = 69
val testII = 96
class A(override val i: Int, override val ii: Int) : I, II
val testI = 69
val testII = 96
val a = A(testI, testII)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
val amqpSchema = obj.envelope.schema.corruptName(listOf(
val amqpSchema = obj.envelope.schema.mangleName(listOf(
classTestName("A"),
"${this.javaClass.`package`.name}.I",
"${this.javaClass.`package`.name}.II"))
val aName = corruptName(classTestName("A"))
val iName = corruptName("${this.javaClass.`package`.name}.I")
val iiName = corruptName("${this.javaClass.`package`.name}.II")
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()
/* 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
and each having A as a dependent */
// 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
// and each having A as a dependent
assertEquals(2, carpenterSchema.carpenterSchemas.size)
assertNotNull(carpenterSchema.carpenterSchemas.find { it.name == iName })
assertNotNull(carpenterSchema.carpenterSchemas.find { it.name == iiName })
@ -438,8 +391,8 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
assertNotNull(carpenterSchema.dependencies[aName]!!.second.find { it == iiName })
val mc = MetaCarpenter(carpenterSchema)
mc.build()
assertEquals(0, mc.schemas.carpenterSchemas.size)
assertEquals(0, mc.schemas.dependencies.size)
assertEquals(0, mc.schemas.dependsOn.size)
@ -451,58 +404,56 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun nestedInterfacesAndImplementation() {
val testI = 7
val testIII = 11
class A(override val i: Int, override val iii: Int) : III
val testI = 7
val testIII = 11
val a = A(testI, testIII)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
val amqpSchema = obj.envelope.schema.corruptName(listOf(
val amqpSchema = obj.envelope.schema.mangleName(listOf(
classTestName("A"),
"${this.javaClass.`package`.name}.I",
"${this.javaClass.`package`.name}.III"))
val aName = corruptName(classTestName("A"))
val iName = corruptName("${this.javaClass.`package`.name}.I")
val iiiName = corruptName("${this.javaClass.`package`.name}.III")
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()
/* Since A depends on III and III extends I we will have to construct them
* in that reverse order (I -> III -> A) */
// Since A depends on III and III extends I we will have to construct them
// in that reverse order (I -> III -> A)
assertEquals(1, carpenterSchema.carpenterSchemas.size)
assertNotNull(carpenterSchema.carpenterSchemas.find { it.name == iName })
assertNull(carpenterSchema.carpenterSchemas.find { it.name == iiiName })
assertNull(carpenterSchema.carpenterSchemas.find { it.name == aName })
/* I has III as a direct dependent and A as an indirect one */
// I has III as a direct dependent and A as an indirect one
assert(iName in carpenterSchema.dependsOn)
assertEquals(2, carpenterSchema.dependsOn[iName]?.size)
assertNotNull(carpenterSchema.dependsOn[iName]?.find({ it == iiiName }))
assertNotNull(carpenterSchema.dependsOn[iName]?.find({ it == aName }))
/* III has A as a dependent */
// III has A as a dependent
assert(iiiName in carpenterSchema.dependsOn)
assertEquals(1, carpenterSchema.dependsOn[iiiName]?.size)
assertNotNull(carpenterSchema.dependsOn[iiiName]?.find { it == aName })
/* converly III depends on I */
// conversly III depends on I
assert(iiiName in carpenterSchema.dependencies)
assertEquals(1, carpenterSchema.dependencies[iiiName]!!.second.size)
assertNotNull(carpenterSchema.dependencies[iiiName]!!.second.find { it == iName })
/* and A depends on III and I*/
// and A depends on III and I
assert(aName in carpenterSchema.dependencies)
assertEquals(2, carpenterSchema.dependencies[aName]!!.second.size)
assertNotNull(carpenterSchema.dependencies[aName]!!.second.find { it == iiiName })
assertNotNull(carpenterSchema.dependencies[aName]!!.second.find { it == iName })
val mc = MetaCarpenter(carpenterSchema)
mc.build()
assertEquals(0, mc.schemas.carpenterSchemas.size)
assertEquals(0, mc.schemas.dependencies.size)
assertEquals(0, mc.schemas.dependsOn.size)
@ -512,5 +463,3 @@ class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
assert(iiiName in mc.objects)
}
}

View File

@ -1,7 +1,6 @@
package net.corda.core.serialization.carpenter
import net.corda.core.serialization.carpenter.test.AmqpCarpenterBase
import net.corda.core.serialization.carpenter.CarpenterSchemas
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.amqp.*
@ -13,14 +12,12 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun twoInts() {
val testA = 10
val testB = 20
@CordaSerializable
data class A(val a: Int, val b: Int)
var a = A(testA, testB)
val testA = 10
val testB = 20
val a = A(testA, testB)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)
@ -31,7 +28,7 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
assertEquals(1, obj.envelope.schema.types.size)
assert(obj.envelope.schema.types[0] is CompositeType)
var amqpSchema = obj.envelope.schema.types[0] as CompositeType
val amqpSchema = obj.envelope.schema.types[0] as CompositeType
assertEquals(2, amqpSchema.fields.size)
assertEquals("a", amqpSchema.fields[0].name)
@ -48,7 +45,6 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
assertNotEquals(null, aSchema)
val pinochio = ClassCarpenter().build(aSchema!!)
val p = pinochio.constructors[0].newInstance(testA, testB)
assertEquals(pinochio.getMethod("getA").invoke(p), amqpObj.a)
@ -57,14 +53,12 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun intAndStr() {
val testA = 10
val testB = "twenty"
@CordaSerializable
data class A(val a: Int, val b: String)
val testA = 10
val testB = "twenty"
val a = A(testA, testB)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)
@ -92,7 +86,6 @@ class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
assertNotEquals(null, aSchema)
val pinochio = ClassCarpenter().build(aSchema!!)
val p = pinochio.constructors[0].newInstance(testA, testB)
assertEquals(pinochio.getMethod("getA").invoke(p), amqpObj.a)

View File

@ -1,23 +1,19 @@
package net.corda.core.serialization.carpenter
import net.corda.core.serialization.carpenter.test.AmqpCarpenterBase
import net.corda.core.serialization.carpenter.CarpenterSchemas
import net.corda.core.serialization.CordaSerializable
import net.corda.core.serialization.amqp.*
import org.junit.Test
import kotlin.test.assertEquals
class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun singleInteger() {
val test = 10
@CordaSerializable
data class A(val a: Int)
val test = 10
val a = A(test)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
@ -39,7 +35,6 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!!
val aBuilder = ClassCarpenter().build(aSchema)
val p = aBuilder.constructors[0].newInstance(test)
assertEquals(aBuilder.getMethod("getA").invoke(p), amqpObj.a)
@ -47,11 +42,10 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun singleString() {
val test = "ten"
@CordaSerializable
data class A(val a: String)
val test = "ten"
val a = A(test)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
@ -64,13 +58,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
assert(obj.envelope.schema.types[0] is CompositeType)
val amqpSchema = obj.envelope.schema.types[0] as CompositeType
val carpenterSchema = CarpenterSchemas.newInstance()
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }!!
val aBuilder = ClassCarpenter().build(aSchema)
val p = aBuilder.constructors[0].newInstance(test)
assertEquals(aBuilder.getMethod("getA").invoke(p), amqpObj.a)
@ -78,13 +70,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun singleLong() {
val test = 10L
@CordaSerializable
data class A(val a: Long)
val test = 10L
val a = A(test)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)
@ -112,13 +102,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun singleShort() {
val test = 10.toShort()
@CordaSerializable
data class A(val a: Short)
val test = 10.toShort()
val a = A(test)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)
@ -146,13 +134,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun singleDouble() {
val test = 10.0
@CordaSerializable
data class A(val a: Double)
val test = 10.0
val a = A(test)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)
@ -180,13 +166,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
@Test
fun singleFloat() {
val test: Float = 10.0F
@CordaSerializable
data class A(val a: Float)
val test: Float = 10.0F
val a = A(test)
val obj = DeserializationInput(factory).deserializeAndReturnEnvelope(serialise(a))
assert(obj.obj is A)