mirror of
https://github.com/corda/corda.git
synced 2025-01-19 11:16:54 +00:00
Add recursive dependency resolution to schema generation
A complete amqp schema can now be used to generate a set of carpetner schemas representing all of the classes not found on the deserialzing end. A dependency and depdendent chain is setup such that all classes are created in the order required Squashed commit messages: * IntelliJ reformat of the code * Merge the interface synthesis changes and rebase onto the tip of master Somethign is very broken in the AMQP -> Carpenter schema code but want a commit so I at least know the actual carpenter is merged * Nested schema creation now works with dependencies recursvly created in the carpenter * Unit test fixes * Remove spurious prints from tests * Remove warnings * Don't add cladd member dep by name Since that's the name of the field, not the type we depend on. If we do we'll never actually be able to craft the type as the dependency chain will be horribly broken Various bug fixes
This commit is contained in:
parent
ce172887d0
commit
b4a62722fc
@ -15,7 +15,9 @@ import java.lang.reflect.Type
|
||||
import java.lang.reflect.TypeVariable
|
||||
import java.util.*
|
||||
|
||||
import net.corda.core.serialization.ClassCarpenterSchema
|
||||
import net.corda.core.serialization.carpenter.CarpenterSchemas
|
||||
import net.corda.core.serialization.carpenter.Schema as CarpenterSchema
|
||||
import net.corda.core.serialization.carpenter.CarpenterSchemaFactory
|
||||
|
||||
// TODO: get an assigned number as per AMQP spec
|
||||
val DESCRIPTOR_TOP_32BITS: Long = 0xc0da0000
|
||||
@ -25,6 +27,24 @@ 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
|
||||
@ -91,28 +111,12 @@ data class Schema(val types: List<TypeNotation>) : DescribedType {
|
||||
override fun toString(): String = types.joinToString("\n")
|
||||
|
||||
fun carpenterSchema(loaders : List<ClassLoader> = listOf<ClassLoader>(ClassLoader.getSystemClassLoader()))
|
||||
: List<ClassCarpenterSchema>
|
||||
: CarpenterSchemas
|
||||
{
|
||||
var rtn = mutableListOf<ClassCarpenterSchema>()
|
||||
var rtn = CarpenterSchemas.newInstance()
|
||||
|
||||
for (type in types) {
|
||||
if (type is CompositeType) {
|
||||
var foundIt = false
|
||||
for (loader in loaders) {
|
||||
try {
|
||||
loader.loadClass(type.name)
|
||||
foundIt = true
|
||||
break
|
||||
} catch (e: ClassNotFoundException) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if (foundIt) continue
|
||||
else {
|
||||
rtn.add(type.carpenterSchema())
|
||||
}
|
||||
}
|
||||
types.filterIsInstance<CompositeType>().forEach {
|
||||
it.carpenterSchema(classLoaders = loaders, carpenterSchemas = rtn)
|
||||
}
|
||||
|
||||
return rtn
|
||||
@ -199,17 +203,9 @@ data class Field(var name: String, val type: String, val requires: List<String>,
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
inline fun isKnownClass (type : String) : Class<*> {
|
||||
try {
|
||||
return ClassLoader.getSystemClassLoader().loadClass(type)
|
||||
}
|
||||
catch (e: ClassNotFoundException) {
|
||||
// call carpenter
|
||||
throw IllegalArgumentException ("${type} - ${name} - pants")
|
||||
}
|
||||
}
|
||||
|
||||
fun getPrimType() = when (type) {
|
||||
fun getTypeAsClass(
|
||||
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())
|
||||
) = when (type) {
|
||||
"int" -> Int::class.javaPrimitiveType!!
|
||||
"string" -> String::class.java
|
||||
"short" -> Short::class.javaPrimitiveType!!
|
||||
@ -217,10 +213,27 @@ data class Field(var name: String, val type: String, val requires: List<String>,
|
||||
"char" -> Char::class.javaPrimitiveType!!
|
||||
"boolean" -> Boolean::class.javaPrimitiveType!!
|
||||
"double" -> Double::class.javaPrimitiveType!!
|
||||
"float" -> Double::class.javaPrimitiveType!!
|
||||
"*" -> isKnownClass(requires[0])
|
||||
else -> isKnownClass(type)
|
||||
"float" -> Float::class.javaPrimitiveType!!
|
||||
"*" -> classLoaders.loadIfExists(requires[0])
|
||||
else -> classLoaders.loadIfExists(type)
|
||||
}
|
||||
|
||||
fun validateType(
|
||||
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!!
|
||||
"*" -> if (classLoaders.exists(requires[0])) requires[0] else null
|
||||
else -> if (classLoaders.exists (type)) type else null
|
||||
}
|
||||
|
||||
fun typeAsString() = if (type =="*") requires[0] else type
|
||||
}
|
||||
|
||||
sealed class TypeNotation : DescribedType {
|
||||
@ -287,32 +300,69 @@ data class CompositeType(override var name: String, override val label: String?,
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun carpenterSchema(classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())) : ClassCarpenterSchema {
|
||||
var m : MutableMap<String, Class<out Any?>> = mutableMapOf()
|
||||
/** if we can load the class then we MUST know about all of it's sub elements,
|
||||
otherwise we couldn't know about this */
|
||||
private fun validateKnown (
|
||||
classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader()))
|
||||
{
|
||||
fields.forEach {
|
||||
if (it.validateType(classLoaders) == null) throw UncarpentableException (name, it.name, it.type)
|
||||
}
|
||||
}
|
||||
|
||||
fields.forEach { m[it.name] = it.getPrimType() }
|
||||
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)
|
||||
|
||||
var providesList = mutableListOf<Class<*>>()
|
||||
|
||||
for (iface in provides) {
|
||||
var found = false
|
||||
for (loader in classLoaders) {
|
||||
try {
|
||||
providesList.add (loader.loadClass(iface))
|
||||
found = true
|
||||
break
|
||||
}
|
||||
catch (e: ClassNotFoundException) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (found == false) {
|
||||
println ("This needs to work but it wont - ${iface}")
|
||||
}
|
||||
else println ("found it ${iface}")
|
||||
if (!force) return
|
||||
}
|
||||
|
||||
return ClassCarpenterSchema (name, m, interfaces = providesList)
|
||||
val providesList = mutableListOf<Class<*>>()
|
||||
|
||||
var isInterface = false
|
||||
var isCreatable = true
|
||||
|
||||
provides.forEach {
|
||||
if (name.equals(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, Class<out Any?>> = mutableMapOf()
|
||||
|
||||
fields.forEach {
|
||||
try {
|
||||
m[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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,10 @@ import org.objectweb.asm.Type
|
||||
import java.lang.Character.isJavaIdentifierPart
|
||||
import java.lang.Character.isJavaIdentifierStart
|
||||
|
||||
import net.corda.core.serialization.carpenter.Schema
|
||||
import net.corda.core.serialization.carpenter.ClassSchema
|
||||
import net.corda.core.serialization.carpenter.InterfaceSchema
|
||||
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
@ -64,6 +68,15 @@ interface SimpleFieldAccess {
|
||||
*
|
||||
* Equals/hashCode methods are not yet supported.
|
||||
*/
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoader) {
|
||||
fun load(name: String, bytes: ByteArray) = defineClass(name, bytes, 0, bytes.size)
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
class ClassCarpenter {
|
||||
// TODO: Generics.
|
||||
// TODO: Sandbox the generated code when a security manager is in use.
|
||||
@ -159,18 +172,13 @@ class ClassCarpenter {
|
||||
}
|
||||
}
|
||||
|
||||
private class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoader) {
|
||||
fun load(name: String, bytes: ByteArray) = defineClass(name, bytes, 0, bytes.size)
|
||||
}
|
||||
|
||||
private val classloader = CarpenterClassLoader()
|
||||
|
||||
fun classLoader() = classloader as ClassLoader
|
||||
val classloader = CarpenterClassLoader()
|
||||
|
||||
private val _loaded = HashMap<String, Class<*>>()
|
||||
private val String.jvm: String get() = replace(".", "/")
|
||||
|
||||
/** Returns a snapshot of the currently loaded classes as a map of full class name (package names+dots) -> class object */
|
||||
fun loaded() : Map<String, Class<*>> = HashMap(_loaded)
|
||||
val loaded: Map<String, Class<*>> = HashMap(_loaded)
|
||||
|
||||
/**
|
||||
* Generate bytecode for the given schema and load into the JVM. The returned class object can be used to
|
||||
@ -178,17 +186,18 @@ class ClassCarpenter {
|
||||
*
|
||||
* @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: ClassCarpenterSchema): Class<*> {
|
||||
fun build(schema: Schema): Class<*> {
|
||||
validateSchema(schema)
|
||||
// Walk up the inheritance hierarchy and then start walking back down once we either hit the top, or
|
||||
// find a class we haven't generated yet.
|
||||
val hierarchy = ArrayList<ClassCarpenterSchema>()
|
||||
val hierarchy = ArrayList<Schema>()
|
||||
hierarchy += schema
|
||||
var cursor = schema.superclass
|
||||
while (cursor != null && cursor.name !in _loaded) {
|
||||
hierarchy += cursor
|
||||
cursor = cursor.superclass
|
||||
}
|
||||
|
||||
hierarchy.reversed().forEach {
|
||||
when (it) {
|
||||
is InterfaceSchema -> generateInterface(it)
|
||||
@ -196,6 +205,8 @@ class ClassCarpenter {
|
||||
}
|
||||
}
|
||||
|
||||
assert (schema.name in _loaded)
|
||||
|
||||
return _loaded[schema.name]!!
|
||||
}
|
||||
|
||||
@ -288,7 +299,8 @@ class ClassCarpenter {
|
||||
|
||||
private fun ClassWriter.generateGetters(schema: Schema) {
|
||||
for ((name, type) in schema.fields) {
|
||||
with(visitMethod(ACC_PUBLIC, "get" + name.capitalize(), "()" + type.descriptor, null, null)) {
|
||||
val opcodes = ACC_PUBLIC
|
||||
with(visitMethod(opcodes, "get" + name.capitalize(), "()" + type.descriptor, null, null)) {
|
||||
type.addNullabilityAnnotation(this)
|
||||
visitCode()
|
||||
visitVarInsn(ALOAD, 0) // Load 'this'
|
||||
@ -305,7 +317,6 @@ class ClassCarpenter {
|
||||
visitEnd()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun ClassWriter.generateAbstractGetters(schema: Schema) {
|
||||
|
@ -0,0 +1,28 @@
|
||||
package net.corda.core.serialization.carpenter
|
||||
|
||||
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>>) {
|
||||
companion object CarpenterSchemaConstructor {
|
||||
fun newInstance(): CarpenterSchemas {
|
||||
return CarpenterSchemas(
|
||||
mutableListOf<Schema>(),
|
||||
mutableMapOf<String, Pair<TypeNotation, MutableList<String>>>(),
|
||||
mutableMapOf<String, MutableList<String>>())
|
||||
}
|
||||
}
|
||||
|
||||
fun addDepPair(type: TypeNotation, dependant: String, dependee: String) {
|
||||
fun String.name() = this.split ('.').last().split('$').last()
|
||||
println ("add dep ${dependant.name()} on ${dependee.name()}")
|
||||
dependsOn.computeIfAbsent(dependee, { mutableListOf<String>() }).add(dependant)
|
||||
dependencies.computeIfAbsent(dependant, { Pair(type, mutableListOf<String>()) }).second.add(dependee)
|
||||
}
|
||||
|
||||
|
||||
val size
|
||||
get() = carpenterSchemas.size
|
||||
}
|
@ -34,11 +34,23 @@ class ClassSchema(
|
||||
fields: Map<String, Class<out Any?>>,
|
||||
superclass: Schema? = null,
|
||||
interfaces: List<Class<*>> = emptyList()
|
||||
) : ClassCarpenter.Schema (name, fields, superclass, interfaces)
|
||||
) : Schema (name, fields, superclass, interfaces)
|
||||
|
||||
class InterfaceSchema(
|
||||
name: String,
|
||||
fields: Map<String, Class<out Any?>>,
|
||||
superclass: Schema? = null,
|
||||
interfaces: List<Class<*>> = emptyList()
|
||||
) : ClassCarpenter.Schema (name, fields, superclass, interfaces)
|
||||
) : Schema (name, fields, superclass, interfaces)
|
||||
|
||||
object CarpenterSchemaFactory {
|
||||
fun newInstance (
|
||||
name: String,
|
||||
fields: Map<String, Class<out Any?>>,
|
||||
superclass: Schema? = null,
|
||||
interfaces: List<Class<*>> = emptyList(),
|
||||
isInterface: Boolean = false
|
||||
) : Schema =
|
||||
if (isInterface) InterfaceSchema (name, fields, superclass, interfaces)
|
||||
else ClassSchema (name, fields, superclass, interfaces)
|
||||
}
|
||||
|
@ -8,31 +8,11 @@ import java.beans.Introspector
|
||||
import kotlin.test.assertNotEquals
|
||||
|
||||
class ClassCarpenterTest {
|
||||
/*
|
||||
cw.visitInnerClass(
|
||||
"net/corda/carpenter/ClassCarpenterTest$DummyInterface",
|
||||
"net/corda/carpenter/ClassCarpenterTest",
|
||||
"DummyInterface",
|
||||
ACC_PUBLIC + ACC_STATIC + ACC_ABSTRACT + ACC_INTERFACE);
|
||||
*/
|
||||
interface DummyInterface {
|
||||
val a: String
|
||||
val b: Int
|
||||
}
|
||||
|
||||
/*
|
||||
cw.visitInnerClass(
|
||||
"net/corda/carpenter/ClassCarpenterTest$Dummy",
|
||||
"net/corda/carpenter/ClassCarpenterTest",
|
||||
"Dummy",
|
||||
ACC_PUBLIC + ACC_FINAL + ACC_STATIC);
|
||||
*/
|
||||
class Dummy (override val a: String, override val b: Int) : DummyInterface
|
||||
|
||||
val dummy = Dummy ("hi", 1)
|
||||
val dummy2 = Dummy2 ("hi", 1)
|
||||
|
||||
|
||||
val cc = ClassCarpenter()
|
||||
|
||||
// We have to ignore synthetic fields even though ClassCarpenter doesn't create any because the JaCoCo
|
||||
@ -191,7 +171,7 @@ class ClassCarpenterTest {
|
||||
assertEquals(iface.declaredMethods.size, 1)
|
||||
assertEquals(iface.declaredMethods[0].name, "getA")
|
||||
|
||||
val schema2 = ClassCarpenter.ClassSchema(
|
||||
val schema2 = ClassSchema(
|
||||
"gen.Derived",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField (Int::class.java)),
|
||||
interfaces = listOf(iface))
|
||||
@ -217,7 +197,7 @@ class ClassCarpenterTest {
|
||||
"c" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"d" to ClassCarpenter.NonNullableField(String::class.java)))
|
||||
|
||||
val class1 = ClassCarpenter.ClassSchema(
|
||||
val class1 = ClassSchema(
|
||||
"gen.Derived",
|
||||
mapOf(
|
||||
"a" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
@ -241,20 +221,20 @@ class ClassCarpenterTest {
|
||||
|
||||
@Test
|
||||
fun `interface implementing interface`() {
|
||||
val iFace1 = ClassCarpenter.InterfaceSchema(
|
||||
val iFace1 = InterfaceSchema(
|
||||
"gen.Interface1",
|
||||
mapOf(
|
||||
"a" to ClassCarpenter.NonNullableField (Int::class.java),
|
||||
"b" to ClassCarpenter.NonNullableField(String::class.java)))
|
||||
|
||||
val iFace2 = ClassCarpenter.InterfaceSchema(
|
||||
val iFace2 = InterfaceSchema(
|
||||
"gen.Interface2",
|
||||
mapOf(
|
||||
"c" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"d" to ClassCarpenter.NonNullableField(String::class.java)),
|
||||
interfaces = listOf(cc.build(iFace1)))
|
||||
|
||||
val class1 = ClassCarpenter.ClassSchema(
|
||||
val class1 = ClassSchema(
|
||||
"gen.Derived",
|
||||
mapOf(
|
||||
"a" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
|
@ -0,0 +1,53 @@
|
||||
package net.corda.carpenter
|
||||
|
||||
import net.corda.core.serialization.carpenter.CarpenterSchemas
|
||||
import net.corda.core.serialization.carpenter.Schema
|
||||
|
||||
import net.corda.core.serialization.amqp.CompositeType
|
||||
|
||||
abstract class MetaCarpenterBase (val schemas : CarpenterSchemas) {
|
||||
|
||||
private val cc = ClassCarpenter()
|
||||
val objects = mutableMapOf<String, Class<*>>()
|
||||
|
||||
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 */
|
||||
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 */
|
||||
if (schemas.dependencies[dependent]?.second?.isEmpty() ?: false) {
|
||||
(schemas.dependencies.remove (dependent)?.first as CompositeType).carpenterSchema (
|
||||
classLoaders = listOf<ClassLoader> (
|
||||
ClassLoader.getSystemClassLoader(),
|
||||
cc.classloader),
|
||||
carpenterSchemas = schemas)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun build()
|
||||
}
|
||||
|
||||
class MetaCarpenter (schemas : CarpenterSchemas) : MetaCarpenterBase (schemas) {
|
||||
override fun build() {
|
||||
while (schemas.carpenterSchemas.isNotEmpty()) {
|
||||
val newObject = schemas.carpenterSchemas.removeAt(0)
|
||||
step (newObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestMetaCarpenter (schemas : CarpenterSchemas) : MetaCarpenterBase (schemas) {
|
||||
override fun build() {
|
||||
println ("TestMetaCarpenter::build")
|
||||
if (schemas.carpenterSchemas.isEmpty()) return
|
||||
step (schemas.carpenterSchemas.removeAt(0))
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package net.corda.carpenter.test
|
||||
|
||||
import net.corda.core.serialization.amqp.CompositeType
|
||||
import net.corda.core.serialization.amqp.Field
|
||||
import net.corda.core.serialization.amqp.Schema
|
||||
import net.corda.core.serialization.amqp.TypeNotation
|
||||
import net.corda.core.serialization.amqp.SerializerFactory
|
||||
import net.corda.core.serialization.amqp.SerializationOutput
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
fun curruptName(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.curruptName (names: List<String>) : Schema {
|
||||
val newTypes : MutableList<TypeNotation> = mutableListOf()
|
||||
|
||||
for (type in types) {
|
||||
val newName = if (type.name in names) curruptName (type.name) else type.name
|
||||
|
||||
val newProvides = type.provides.map {
|
||||
it -> if (it in names) curruptName (it) else it
|
||||
}
|
||||
|
||||
val newFields = mutableListOf<Field>()
|
||||
|
||||
(type as CompositeType).fields.forEach {
|
||||
val type = if (it.type in names) curruptName (it.type) else it.type
|
||||
|
||||
val requires = if (it.requires.isNotEmpty() && (it.requires[0] in names))
|
||||
listOf (curruptName (it.requires[0])) else it.requires
|
||||
|
||||
newFields.add (it.copy (type=type, requires=requires))
|
||||
}
|
||||
|
||||
newTypes.add (type.copy (name=newName, provides=newProvides, fields=newFields))
|
||||
}
|
||||
|
||||
return Schema (types=newTypes)
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
open class AmqpCarpenterBase {
|
||||
var factory = SerializerFactory()
|
||||
|
||||
fun serialise (clazz : Any) = SerializationOutput(factory).serialize(clazz)
|
||||
fun testName() = Thread.currentThread().stackTrace[2].methodName
|
||||
inline fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
@ -2,17 +2,25 @@ package net.corda.carpenter
|
||||
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.amqp.*
|
||||
import net.corda.core.serialization.ClassCarpenterSchema
|
||||
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import net.corda.carpenter.test.*
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class Inheritance {
|
||||
private var factory = SerializerFactory()
|
||||
@CordaSerializable
|
||||
interface I_ {
|
||||
val a: Int
|
||||
}
|
||||
|
||||
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
||||
/*
|
||||
* Where a class has a member that is also a composite type or interface
|
||||
*/
|
||||
class CompositeMembers : AmqpCarpenterBase() {
|
||||
|
||||
@Test
|
||||
fun nestedInts() {
|
||||
fun bothKnown () {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
|
||||
@ -20,9 +28,9 @@ class Inheritance {
|
||||
data class A(val a: Int)
|
||||
|
||||
@CordaSerializable
|
||||
class B (val a: A, var b: Int)
|
||||
data class B (val a: A, var b: Int)
|
||||
|
||||
var b = B(A(testA), testB)
|
||||
val b = B(A(testA), testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||
|
||||
@ -36,9 +44,6 @@ class Inheritance {
|
||||
assert(obj.second.schema.types[0] is CompositeType)
|
||||
assert(obj.second.schema.types[1] is CompositeType)
|
||||
|
||||
println (obj.second.schema.types[0] as CompositeType)
|
||||
println (obj.second.schema.types[1] as CompositeType)
|
||||
|
||||
var amqpSchemaA : CompositeType? = null
|
||||
var amqpSchemaB : CompositeType? = null
|
||||
|
||||
@ -52,31 +57,266 @@ class Inheritance {
|
||||
assert (amqpSchemaA != null)
|
||||
assert (amqpSchemaB != null)
|
||||
|
||||
/*
|
||||
* 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)
|
||||
|
||||
assertEquals("int", amqpSchemaA.fields[0].type)
|
||||
|
||||
assertEquals(2, amqpSchemaB?.fields?.size)
|
||||
assertEquals("a", amqpSchemaB!!.fields[0].name)
|
||||
assertEquals("${this.javaClass.name}\$nestedInts\$A", amqpSchemaB!!.fields[0].type)
|
||||
assertEquals("b", amqpSchemaB!!.fields[1].name)
|
||||
assertEquals("int", amqpSchemaB!!.fields[1].type)
|
||||
assertEquals(classTestName("A"), amqpSchemaB.fields[0].type)
|
||||
assertEquals("b", amqpSchemaB.fields[1].name)
|
||||
assertEquals("int", amqpSchemaB.fields[1].type)
|
||||
|
||||
var ccA = ClassCarpenter().build(amqpSchemaA.carpenterSchema())
|
||||
var ccB = ClassCarpenter().build(amqpSchemaB.carpenterSchema())
|
||||
val metaSchema = obj.second.schema.carpenterSchema()
|
||||
|
||||
/*
|
||||
* Since A is known to the JVM we can't constuct B with and instance of the carpented A but
|
||||
* need to use the defined one above
|
||||
*/
|
||||
val instanceA = ccA.constructors[0].newInstance(testA)
|
||||
val instanceB = ccB.constructors[0].newInstance(A (testA), testB)
|
||||
/* 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())
|
||||
}
|
||||
|
||||
assertEquals (ccA.getMethod("getA").invoke(instanceA), amqpObj.a.a)
|
||||
assertEquals ((ccB.getMethod("getA").invoke(instanceB) as A).a, amqpObj.a.a)
|
||||
assertEquals (ccB.getMethod("getB").invoke(instanceB), amqpObj.b)
|
||||
/* 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
|
||||
val testB = 20
|
||||
|
||||
@CordaSerializable
|
||||
data class A(override val a: Int) : I_
|
||||
|
||||
@CordaSerializable
|
||||
data class B(val a: A, var b: Int)
|
||||
val b = B(A(testA), testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||
val amqpSchema = obj.second.schema.curruptName(listOf (classTestName ("A")))
|
||||
|
||||
assert(obj.first is B)
|
||||
|
||||
amqpSchema.carpenterSchema()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ParentIsUnknown () {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
|
||||
@CordaSerializable
|
||||
data class A(override val a: Int) : I_
|
||||
|
||||
@CordaSerializable
|
||||
data class B(val a: A, var b: Int)
|
||||
val b = B(A(testA), testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||
|
||||
assert(obj.first is B)
|
||||
|
||||
val amqpSchema = obj.second.schema.curruptName(listOf (classTestName ("B")))
|
||||
|
||||
val carpenterSchema = amqpSchema.carpenterSchema()
|
||||
|
||||
assertEquals (1, carpenterSchema.size)
|
||||
|
||||
val metaCarpenter = MetaCarpenter (carpenterSchema)
|
||||
|
||||
metaCarpenter.build()
|
||||
|
||||
assert (curruptName(classTestName("B")) in metaCarpenter.objects)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun BothUnkown () {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
|
||||
@CordaSerializable
|
||||
data class A(override val a: Int) : I_
|
||||
|
||||
@CordaSerializable
|
||||
data class B(val a: A, var b: Int)
|
||||
val b = B(A(testA), testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||
|
||||
assert(obj.first is B)
|
||||
|
||||
val amqpSchema = obj.second.schema.curruptName(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 */
|
||||
assertEquals (1, carpenterSchema.size)
|
||||
assertEquals (curruptName(classTestName("A")), carpenterSchema.carpenterSchemas.first().name)
|
||||
assertEquals (1, carpenterSchema.dependencies.size)
|
||||
assert (curruptName(classTestName("B")) in carpenterSchema.dependencies)
|
||||
assertEquals (1, carpenterSchema.dependsOn.size)
|
||||
assert (curruptName(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 */
|
||||
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 (curruptName(classTestName("A")) in metaCarpenter.objects)
|
||||
assertFalse (curruptName(classTestName("B")) in metaCarpenter.objects)
|
||||
|
||||
assertEquals (1, carpenterSchema.carpenterSchemas.size)
|
||||
assertEquals (curruptName(classTestName("B")), carpenterSchema.carpenterSchemas.first().name)
|
||||
assertTrue (carpenterSchema.dependencies.isEmpty())
|
||||
assertTrue (carpenterSchema.dependsOn.isEmpty())
|
||||
|
||||
/* second manual iteration, will carpent B */
|
||||
metaCarpenter.build()
|
||||
assert (curruptName(classTestName("A")) in metaCarpenter.objects)
|
||||
assert (curruptName(classTestName("B")) in metaCarpenter.objects)
|
||||
|
||||
assertTrue (carpenterSchema.carpenterSchemas.isEmpty())
|
||||
}
|
||||
|
||||
@Test(expected = UncarpentableException::class)
|
||||
fun nestedIsUnkownInherited () {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
val testC = 30
|
||||
|
||||
@CordaSerializable
|
||||
open class A(val a: Int)
|
||||
|
||||
@CordaSerializable
|
||||
class B(a: Int, var b: Int) : A (a)
|
||||
|
||||
@CordaSerializable
|
||||
data class C(val b: B, var c: Int)
|
||||
|
||||
val c = C(B(testA, testB), testC)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(c))
|
||||
|
||||
assert(obj.first is C)
|
||||
|
||||
val amqpSchema = obj.second.schema.curruptName(listOf (classTestName ("A"), classTestName ("B")))
|
||||
|
||||
amqpSchema.carpenterSchema()
|
||||
}
|
||||
|
||||
@Test(expected = UncarpentableException::class)
|
||||
fun nestedIsUnknownInheritedUnkown () {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
val testC = 30
|
||||
|
||||
@CordaSerializable
|
||||
open class A(val a: Int)
|
||||
|
||||
@CordaSerializable
|
||||
class B(a: Int, var b: Int) : A (a)
|
||||
|
||||
@CordaSerializable
|
||||
data class C(val b: B, var c: Int)
|
||||
|
||||
val c = C(B(testA, testB), testC)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(c))
|
||||
|
||||
assert(obj.first is C)
|
||||
|
||||
val amqpSchema = obj.second.schema.curruptName(listOf (classTestName ("A"), classTestName ("B")))
|
||||
|
||||
amqpSchema.carpenterSchema()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parentsIsUnknownWithUnkownInheritedMember () {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
val testC = 30
|
||||
|
||||
@CordaSerializable
|
||||
open class A(val a: Int)
|
||||
|
||||
@CordaSerializable
|
||||
class B(a: Int, var b: Int) : A (a)
|
||||
|
||||
@CordaSerializable
|
||||
data class C(val b: B, var c: Int)
|
||||
|
||||
val c = C(B(testA, testB), testC)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(c))
|
||||
|
||||
assert(obj.first is C)
|
||||
|
||||
val amqpSchema = obj.second.schema.curruptName(listOf (classTestName ("A"), classTestName ("B")))
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* In this case B holds an element of Interface I_ which is an A but we don't know of A
|
||||
* but we do know about I_
|
||||
*/
|
||||
@Test
|
||||
fun nestedIsInterfaceToUnknown () {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
|
||||
@CordaSerializable
|
||||
data class A(override val a: Int) : I_
|
||||
|
||||
@CordaSerializable
|
||||
data class B(val a: A, var b: Int)
|
||||
val b = B(A(testA), testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||
|
||||
assert(obj.first is B)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nestedIsUnknownInterface() {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
|
||||
@CordaSerializable
|
||||
data class A(override val a: Int) : I_
|
||||
|
||||
@CordaSerializable
|
||||
data class B(val a: A, var b: Int)
|
||||
val b = B(A(testA), testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||
|
||||
assert(obj.first is B)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ParentsIsInterfaceToUnkown() {
|
||||
val testA = 10
|
||||
val testB = 20
|
||||
|
||||
@CordaSerializable
|
||||
data class A(override val a: Int) : I_
|
||||
|
||||
@CordaSerializable
|
||||
data class B(val a: A, var b: Int)
|
||||
val b = B(A(testA), testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||
|
||||
assert(obj.first is B)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,9 @@ package net.corda.carpenter
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.amqp.*
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import net.corda.carpenter.test.*
|
||||
import net.corda.carpenter.MetaCarpenter
|
||||
import kotlin.test.*
|
||||
|
||||
/*******************************************************************************************************/
|
||||
|
||||
@ -38,42 +40,11 @@ interface IIII {
|
||||
|
||||
/*******************************************************************************************************/
|
||||
|
||||
class InheritanceSchemaToClassCarpenterTests {
|
||||
private var factory = SerializerFactory()
|
||||
|
||||
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
||||
|
||||
fun curruptName(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 curruptName (schema: Schema, names: List<String>) : Schema {
|
||||
val types = schema.types
|
||||
|
||||
val newTypes : MutableList<TypeNotation> = mutableListOf()
|
||||
|
||||
for (type in types) {
|
||||
val newName = if (type.name in names) curruptName (type.name) else type.name
|
||||
|
||||
val newProvides = type.provides.map {
|
||||
it -> if (it in names) curruptName (it) else it
|
||||
}
|
||||
|
||||
val newFields = (type as CompositeType).fields.map {
|
||||
it -> if ( it.requires.isNotEmpty() && it.requires[0] in names)
|
||||
it.copy (requires=listOf (curruptName (it.requires[0]))) else it
|
||||
}
|
||||
|
||||
newTypes.add (type.copy (name=newName, provides=newProvides, fields=newFields))
|
||||
}
|
||||
|
||||
return Schema (types=newTypes)
|
||||
}
|
||||
class InheritanceSchemaToClassCarpenterTests : AmqpCarpenterBase() {
|
||||
|
||||
@Test
|
||||
fun interfaceParent1() {
|
||||
val testJ = 20
|
||||
val testName = "interfaceParent1"
|
||||
|
||||
class A(override val j: Int) : J
|
||||
|
||||
@ -95,17 +66,20 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
it's extremely unlikely we'd need to carpent any classes */
|
||||
assertEquals(0, l1.size)
|
||||
|
||||
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A"))
|
||||
val curruptSchema = serSchema.curruptName (listOf (classTestName ("A")))
|
||||
|
||||
val l2 = curruptSchema.carpenterSchema()
|
||||
|
||||
assertEquals(1, l2.size)
|
||||
val aSchema = l2.carpenterSchemas.find { it.name == curruptName(classTestName("A")) }
|
||||
|
||||
assertEquals(curruptName("${this.javaClass.name}\$$testName\$A"), l2[0].name)
|
||||
assertEquals(1, l2[0].interfaces.size)
|
||||
assertEquals(net.corda.carpenter.J::class.java, l2[0].interfaces[0])
|
||||
assertNotEquals (null, aSchema)
|
||||
|
||||
val aBuilder = ClassCarpenter().build(l2[0])
|
||||
assertEquals(curruptName(classTestName("A")), aSchema!!.name)
|
||||
assertEquals(1, aSchema.interfaces.size)
|
||||
assertEquals(net.corda.carpenter.J::class.java, aSchema.interfaces[0])
|
||||
|
||||
val aBuilder = ClassCarpenter().build(aSchema)
|
||||
|
||||
val objJ = aBuilder.constructors[0].newInstance(testJ)
|
||||
val j = objJ as J
|
||||
@ -119,7 +93,6 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
fun interfaceParent2() {
|
||||
val testJ = 20
|
||||
val testJJ = 40
|
||||
val testName = "interfaceParent2"
|
||||
|
||||
class A(override val j: Int, val jj: Int) : J
|
||||
|
||||
@ -142,17 +115,22 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
it's extremely unlikely we'd need to carpent any classes */
|
||||
assertEquals(0, l1.size)
|
||||
|
||||
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A"))
|
||||
val curruptSchema = serSchema.curruptName (listOf (classTestName("A")))
|
||||
val aName = curruptName(classTestName("A"))
|
||||
|
||||
val l2 = curruptSchema.carpenterSchema()
|
||||
|
||||
assertEquals(1, l2.size)
|
||||
|
||||
assertEquals(curruptName("${this.javaClass.name}\$$testName\$A"), l2[0].name)
|
||||
assertEquals(1, l2[0].interfaces.size)
|
||||
assertEquals(net.corda.carpenter.J::class.java, l2[0].interfaces[0])
|
||||
val aSchema = l2.carpenterSchemas.find { it.name == aName }
|
||||
|
||||
val aBuilder = ClassCarpenter().build(l2[0])
|
||||
assertNotEquals(null, aSchema)
|
||||
|
||||
assertEquals(aName, aSchema!!.name)
|
||||
assertEquals(1, aSchema.interfaces.size)
|
||||
assertEquals(net.corda.carpenter.J::class.java, aSchema.interfaces[0])
|
||||
|
||||
val aBuilder = ClassCarpenter().build(aSchema)
|
||||
|
||||
val objJ = aBuilder.constructors[0].newInstance(testJ, testJJ)
|
||||
val j = objJ as J
|
||||
@ -167,7 +145,6 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
fun multipleInterfaces() {
|
||||
val testI = 20
|
||||
val testII = 40
|
||||
val testName = "multipleInterfaces"
|
||||
|
||||
class A(override val i: Int, override val ii: Int) : I, II
|
||||
|
||||
@ -189,17 +166,22 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
/* 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 curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A"))
|
||||
val l2 = curruptSchema.carpenterSchema()
|
||||
val curruptSchema = serSchema.curruptName (listOf (classTestName ("A")))
|
||||
val l2 = curruptSchema.carpenterSchema()
|
||||
val aName = curruptName(classTestName("A"))
|
||||
|
||||
assertEquals(1, l2.size)
|
||||
|
||||
assertEquals(curruptName("${this.javaClass.name}\$$testName\$A"), l2[0].name)
|
||||
assertEquals(2, l2[0].interfaces.size)
|
||||
assert (net.corda.carpenter.I::class.java in l2[0].interfaces)
|
||||
assert (net.corda.carpenter.II::class.java in l2[0].interfaces)
|
||||
val aSchema = l2.carpenterSchemas.find { it.name == aName }
|
||||
|
||||
val aBuilder = ClassCarpenter().build(l2[0])
|
||||
assertNotEquals(null, aSchema)
|
||||
|
||||
assertEquals(aName, aSchema!!.name)
|
||||
assertEquals(2, aSchema.interfaces.size)
|
||||
assert (net.corda.carpenter.I::class.java in aSchema.interfaces)
|
||||
assert (net.corda.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
|
||||
@ -216,7 +198,6 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
fun nestedInterfaces() {
|
||||
val testI = 20
|
||||
val testIII = 60
|
||||
val testName = "nestedInterfaces"
|
||||
|
||||
class A(override val i: Int, override val iii : Int) : III
|
||||
|
||||
@ -235,17 +216,22 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
it's extremely unlikely we'd need to carpent any classes */
|
||||
assertEquals(0, l1.size)
|
||||
|
||||
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A"))
|
||||
val curruptSchema = serSchema.curruptName (listOf (classTestName ("A")))
|
||||
val l2 = curruptSchema.carpenterSchema()
|
||||
val aName = curruptName(classTestName("A"))
|
||||
|
||||
assertEquals(1, l2.size)
|
||||
|
||||
assertEquals(curruptName("${this.javaClass.name}\$$testName\$A"), l2[0].name)
|
||||
assertEquals(2, l2[0].interfaces.size)
|
||||
assert (net.corda.carpenter.I::class.java in l2[0].interfaces)
|
||||
assert (net.corda.carpenter.III::class.java in l2[0].interfaces)
|
||||
val aSchema = l2.carpenterSchemas.find { it.name == aName }
|
||||
|
||||
val aBuilder = ClassCarpenter().build(l2[0])
|
||||
assertNotEquals(null, aSchema)
|
||||
|
||||
assertEquals(aName, aSchema!!.name)
|
||||
assertEquals(2, aSchema.interfaces.size)
|
||||
assert (net.corda.carpenter.I::class.java in aSchema.interfaces)
|
||||
assert (net.corda.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
|
||||
@ -263,7 +249,6 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
fun memberInterface() {
|
||||
val testI = 25
|
||||
val testIIII = 50
|
||||
val testName = "memberInterface"
|
||||
|
||||
class A(override val i: Int) : I
|
||||
class B(override val i : I, override val iiii : Int) : IIII
|
||||
@ -285,17 +270,18 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
*/
|
||||
assertEquals(4, serSchema.types.size)
|
||||
|
||||
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A",
|
||||
"${this.javaClass.name}\$$testName\$B"))
|
||||
val curruptSchema = serSchema.curruptName (listOf (classTestName ("A"), classTestName ("B")))
|
||||
val cSchema = curruptSchema.carpenterSchema()
|
||||
val aName = curruptName(classTestName("A"))
|
||||
val bName = curruptName(classTestName("B"))
|
||||
|
||||
val cSchema = curruptSchema.carpenterSchema()
|
||||
assertEquals(2, cSchema.size)
|
||||
|
||||
val aCarpenterSchema = cSchema.find { it.name == curruptName("${this.javaClass.name}\$$testName\$A") }
|
||||
val bCarpenterSchema = cSchema.find { it.name == curruptName("${this.javaClass.name}\$$testName\$B") }
|
||||
val aCarpenterSchema = cSchema.carpenterSchemas.find { it.name == aName }
|
||||
val bCarpenterSchema = cSchema.carpenterSchemas.find { it.name == bName }
|
||||
|
||||
assert(aCarpenterSchema != null)
|
||||
assert(bCarpenterSchema != null)
|
||||
assertNotEquals (null, aCarpenterSchema)
|
||||
assertNotEquals (null, bCarpenterSchema)
|
||||
|
||||
val cc = ClassCarpenter()
|
||||
val cc2 = ClassCarpenter()
|
||||
@ -317,13 +303,12 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
bBuilder.constructors[0].newInstance(objA2, testIIII)
|
||||
}
|
||||
|
||||
/* this time remove the nested interface from out set of known classes forcing us
|
||||
to whittle it */
|
||||
@Test
|
||||
/* 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 */
|
||||
@Test(expected = UncarpentableException::class)
|
||||
fun memberInterface2() {
|
||||
val testI = 25
|
||||
val testIIII = 50
|
||||
val testName = "memberInterface2"
|
||||
|
||||
class A(override val i: Int) : I
|
||||
class B(override val i : I, override val iiii : Int) : IIII
|
||||
@ -346,44 +331,185 @@ class InheritanceSchemaToClassCarpenterTests {
|
||||
*/
|
||||
assertEquals(4, serSchema.types.size)
|
||||
|
||||
val curruptSchema = curruptName (serSchema, listOf (
|
||||
"${this.javaClass.name}\$$testName\$A",
|
||||
"${this.javaClass.getPackage().name}.I"))
|
||||
|
||||
|
||||
val carpenterSchema = curruptSchema.carpenterSchema()
|
||||
|
||||
val aCarpenterSchema = carpenterSchema.find { it.name == curruptName("${this.javaClass.name}\$$testName\$A") }
|
||||
// val bCarpenterSchema = carpenterSchema.find { it.name == curruptName("${this.javaClass.getPackage().name}.I") }
|
||||
|
||||
val cc = ClassCarpenter()
|
||||
|
||||
val aBuilder = cc.build (aCarpenterSchema!!)
|
||||
aBuilder.constructors[0].newInstance(testI)
|
||||
|
||||
|
||||
/*
|
||||
|
||||
var cc2 = ClassCarpenter()
|
||||
|
||||
var bBuilder = cc.build(bCarpenterSchema!!)
|
||||
val objB = bBuilder.constructors[0].newInstance(a, testIIII)
|
||||
|
||||
var 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 */
|
||||
val objB2 = bBuilder.constructors[0].newInstance(objA, testIIII)
|
||||
|
||||
/* whittle and instantiate a different A with a new class loader */
|
||||
var aBuilder2 = cc2.build(aCarpenterSchema!!)
|
||||
val objA2 = aBuilder2.constructors[0].newInstance(testI)
|
||||
|
||||
val objB3 = bBuilder.constructors[0].newInstance(objA2, testIIII)
|
||||
*/
|
||||
/* ignore the return as we expect this to throw */
|
||||
serSchema.curruptName (listOf (
|
||||
classTestName("A"), "${this.javaClass.`package`.name}.I")).carpenterSchema()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun interfaceAndImplementation() {
|
||||
val testI = 25
|
||||
|
||||
class A(override val i: Int) : I
|
||||
|
||||
val a = A(testI)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||
|
||||
assert(obj.first is A)
|
||||
|
||||
val serSchema = obj.second.schema
|
||||
|
||||
/*
|
||||
* The classes we're expecting to find:
|
||||
* class A
|
||||
* class A's interface (class I)
|
||||
*/
|
||||
assertEquals(2, serSchema.types.size)
|
||||
|
||||
val amqpSchema = serSchema.curruptName (listOf (classTestName("A"), "${this.javaClass.`package`.name}.I"))
|
||||
|
||||
val aName = curruptName (classTestName("A"))
|
||||
val iName = curruptName ("${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 */
|
||||
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*/
|
||||
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 */
|
||||
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)
|
||||
assertEquals (0, mc.schemas.dependencies.size)
|
||||
assertEquals (0, mc.schemas.dependsOn.size)
|
||||
assertEquals (2, mc.objects.size)
|
||||
assert (aName in mc.objects)
|
||||
assert (iName in mc.objects)
|
||||
|
||||
mc.objects[aName]!!.constructors[0].newInstance(testI)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun twoInterfacesAndImplementation() {
|
||||
val testI = 69
|
||||
val testII = 96
|
||||
|
||||
class A(override val i: Int, override val ii: Int) : I, II
|
||||
|
||||
val a = A(testI, testII)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||
|
||||
val amqpSchema = obj.second.schema.curruptName(listOf(
|
||||
classTestName("A"),
|
||||
"${this.javaClass.`package`.name}.I",
|
||||
"${this.javaClass.`package`.name}.II"))
|
||||
|
||||
val aName = curruptName (classTestName("A"))
|
||||
val iName = curruptName ("${this.javaClass.`package`.name}.I")
|
||||
val iiName = curruptName ("${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 */
|
||||
assertEquals (2, carpenterSchema.carpenterSchemas.size)
|
||||
assertNotNull (carpenterSchema.carpenterSchemas.find { it.name == iName })
|
||||
assertNotNull (carpenterSchema.carpenterSchemas.find { it.name == iiName })
|
||||
assertNull (carpenterSchema.carpenterSchemas.find { it.name == aName })
|
||||
|
||||
assert (iName in carpenterSchema.dependsOn)
|
||||
assertEquals (1, carpenterSchema.dependsOn[iName]?.size)
|
||||
assertNotNull (carpenterSchema.dependsOn[iName]?.find ( { it == aName }))
|
||||
|
||||
assert (iiName in carpenterSchema.dependsOn)
|
||||
assertEquals (1, carpenterSchema.dependsOn[iiName]?.size)
|
||||
assertNotNull (carpenterSchema.dependsOn[iiName]?.find { it == aName })
|
||||
|
||||
assert (aName in carpenterSchema.dependencies)
|
||||
assertEquals (2, carpenterSchema.dependencies[aName]!!.second.size)
|
||||
assertNotNull (carpenterSchema.dependencies[aName]!!.second.find { it == iName })
|
||||
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)
|
||||
assertEquals (3, mc.objects.size)
|
||||
assert (aName in mc.objects)
|
||||
assert (iName in mc.objects)
|
||||
assert (iiName in mc.objects)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun nestedInterfacesAndImplementation() {
|
||||
val testI = 7
|
||||
val testIII = 11
|
||||
|
||||
class A(override val i: Int, override val iii : Int) : III
|
||||
|
||||
val a = A(testI, testIII)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||
|
||||
val amqpSchema = obj.second.schema.curruptName(listOf(
|
||||
classTestName("A"),
|
||||
"${this.javaClass.`package`.name}.I",
|
||||
"${this.javaClass.`package`.name}.III"))
|
||||
|
||||
val aName = curruptName (classTestName("A"))
|
||||
val iName = curruptName ("${this.javaClass.`package`.name}.I")
|
||||
val iiiName = curruptName ("${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) */
|
||||
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 */
|
||||
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 */
|
||||
assert (iiiName in carpenterSchema.dependsOn)
|
||||
assertEquals (1, carpenterSchema.dependsOn[iiiName]?.size)
|
||||
assertNotNull (carpenterSchema.dependsOn[iiiName]?.find { it == aName })
|
||||
|
||||
/* converly 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*/
|
||||
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)
|
||||
assertEquals (3, mc.objects.size)
|
||||
assert (aName in mc.objects)
|
||||
assert (iName in mc.objects)
|
||||
assert (iiiName in mc.objects)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,14 +1,14 @@
|
||||
package net.corda.carpenter
|
||||
|
||||
import net.corda.carpenter.test.AmqpCarpenterBase
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.amqp.*
|
||||
import net.corda.core.serialization.carpenter.CarpenterSchemas
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
|
||||
class MultiMemberCompositeSchemaToClassCarpenterTests {
|
||||
private var factory = SerializerFactory()
|
||||
|
||||
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
||||
class MultiMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
|
||||
|
||||
@Test
|
||||
fun twoInts() {
|
||||
@ -38,7 +38,15 @@ class MultiMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals("b", amqpSchema.fields[1].name)
|
||||
assertEquals("int", amqpSchema.fields[1].type)
|
||||
|
||||
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
assertEquals (1, carpenterSchema.size)
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName ("A") }
|
||||
|
||||
assertNotEquals (null, aSchema)
|
||||
|
||||
val pinochio = ClassCarpenter().build(aSchema!!)
|
||||
|
||||
val p = pinochio.constructors[0].newInstance(testA, testB)
|
||||
|
||||
@ -54,7 +62,7 @@ class MultiMemberCompositeSchemaToClassCarpenterTests {
|
||||
@CordaSerializable
|
||||
data class A(val a: Int, val b: String)
|
||||
|
||||
var a = A(testA, testB)
|
||||
val a = A(testA, testB)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||
|
||||
@ -66,7 +74,7 @@ class MultiMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals(1, obj.second.schema.types.size)
|
||||
assert(obj.second.schema.types[0] is CompositeType)
|
||||
|
||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
val amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
|
||||
assertEquals(2, amqpSchema.fields.size)
|
||||
assertEquals("a", amqpSchema.fields[0].name)
|
||||
@ -74,7 +82,15 @@ class MultiMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals("b", amqpSchema.fields[1].name)
|
||||
assertEquals("string", amqpSchema.fields[1].type)
|
||||
|
||||
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
assertEquals (1, carpenterSchema.size)
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName("A") }
|
||||
|
||||
assertNotEquals(null, aSchema)
|
||||
|
||||
val pinochio = ClassCarpenter().build(aSchema!!)
|
||||
|
||||
val p = pinochio.constructors[0].newInstance(testA, testB)
|
||||
|
||||
|
@ -1,16 +1,14 @@
|
||||
package net.corda.carpenter
|
||||
|
||||
import net.corda.carpenter.test.AmqpCarpenterBase
|
||||
import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.ClassCarpenterSchema
|
||||
import net.corda.core.serialization.amqp.*
|
||||
import net.corda.core.serialization.carpenter.CarpenterSchemas
|
||||
import org.junit.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
|
||||
class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
private var factory = SerializerFactory()
|
||||
|
||||
fun serialise (clazz : Any) = SerializationOutput(factory).serialize(clazz)
|
||||
class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
|
||||
|
||||
@Test
|
||||
fun singleInteger() {
|
||||
@ -35,7 +33,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals ("a", amqpSchema.fields[0].name)
|
||||
assertEquals ("int", amqpSchema.fields[0].type)
|
||||
|
||||
val pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName ("A") }!!
|
||||
val pinochio = ClassCarpenter().build(aSchema)
|
||||
|
||||
val p = pinochio.constructors[0].newInstance (test)
|
||||
|
||||
@ -48,7 +50,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
|
||||
@CordaSerializable
|
||||
data class A(val a : String)
|
||||
var a = A (test)
|
||||
val a = A (test)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
||||
|
||||
@ -59,13 +61,13 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals (1, obj.second.schema.types.size)
|
||||
assert (obj.second.schema.types[0] is CompositeType)
|
||||
|
||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
val amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
|
||||
assertEquals (1, amqpSchema.fields.size)
|
||||
assertEquals ("a", amqpSchema.fields[0].name)
|
||||
assertEquals ("string", amqpSchema.fields[0].type)
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName ("A") }!!
|
||||
val pinochio = ClassCarpenter().build(aSchema)
|
||||
|
||||
val p = pinochio.constructors[0].newInstance (test)
|
||||
|
||||
@ -79,9 +81,9 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
|
||||
@CordaSerializable
|
||||
data class A(val a : Char)
|
||||
var a = A (test)
|
||||
val a = A(test)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||
|
||||
assert (obj.first is A)
|
||||
val amqpObj = obj.first as A
|
||||
@ -91,13 +93,19 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals (1, obj.second.schema.types.size)
|
||||
assert (obj.second.schema.types[0] is CompositeType)
|
||||
|
||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
val amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
|
||||
assertEquals (1, amqpSchema.fields.size)
|
||||
assertEquals ("a", amqpSchema.fields[0].name)
|
||||
assertEquals ("char", amqpSchema.fields[0].type)
|
||||
|
||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
||||
val carpenterSchema = CarpenterSchema.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchema = carpenterSchema, force = true)
|
||||
|
||||
assert (classTestName ("A") in carpenterSchema.carpenterSchemas)
|
||||
|
||||
val aSchema = carpenterSchema.carpenterSchemas[classTestName ("A")]!!
|
||||
val pinochio = ClassCarpenter().build(aSchema)
|
||||
|
||||
val p = pinochio.constructors[0].newInstance (test)
|
||||
|
||||
@ -129,8 +137,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals ("a", amqpSchema.fields[0].name)
|
||||
assertEquals ("long", amqpSchema.fields[0].type)
|
||||
|
||||
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName ("A") }!!
|
||||
val pinochio = ClassCarpenter().build(aSchema)
|
||||
val p = pinochio.constructors[0].newInstance (test)
|
||||
|
||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
||||
@ -160,8 +171,11 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals ("a", amqpSchema.fields[0].name)
|
||||
assertEquals ("short", amqpSchema.fields[0].type)
|
||||
|
||||
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName ("A")}!!
|
||||
val pinochio = ClassCarpenter().build(aSchema)
|
||||
val p = pinochio.constructors[0].newInstance (test)
|
||||
|
||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
||||
@ -207,7 +221,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
@CordaSerializable
|
||||
data class A(val a : Double)
|
||||
|
||||
var a = A (test)
|
||||
val a = A (test)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
||||
|
||||
@ -218,14 +232,17 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals (1, obj.second.schema.types.size)
|
||||
assert (obj.second.schema.types[0] is CompositeType)
|
||||
|
||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
val amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
|
||||
assertEquals (1, amqpSchema.fields.size)
|
||||
assertEquals ("a", amqpSchema.fields[0].name)
|
||||
assertEquals ("double", amqpSchema.fields[0].type)
|
||||
|
||||
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName ("A")}!!
|
||||
val pinochio = ClassCarpenter().build(aSchema)
|
||||
val p = pinochio.constructors[0].newInstance (test)
|
||||
|
||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
||||
@ -233,12 +250,12 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
|
||||
@Test
|
||||
fun singleFloat() {
|
||||
val test = 10.0F
|
||||
val test : Float = 10.0F
|
||||
|
||||
@CordaSerializable
|
||||
data class A(val a : Float)
|
||||
|
||||
var a = A (test)
|
||||
val a = A (test)
|
||||
|
||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
||||
|
||||
@ -249,16 +266,19 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
||||
assertEquals (1, obj.second.schema.types.size)
|
||||
assert (obj.second.schema.types[0] is CompositeType)
|
||||
|
||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
val amqpSchema = obj.second.schema.types[0] as CompositeType
|
||||
|
||||
assertEquals (1, amqpSchema.fields.size)
|
||||
assertEquals ("a", amqpSchema.fields[0].name)
|
||||
assertEquals ("float", amqpSchema.fields[0].type)
|
||||
|
||||
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||
val carpenterSchema = CarpenterSchemas.newInstance()
|
||||
amqpSchema.carpenterSchema(carpenterSchemas = carpenterSchema, force = true)
|
||||
|
||||
val aSchema = carpenterSchema.carpenterSchemas.find { it.name == classTestName ("A") }!!
|
||||
val pinochio = ClassCarpenter().build(aSchema)
|
||||
val p = pinochio.constructors[0].newInstance (test)
|
||||
|
||||
// assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user