mirror of
https://github.com/corda/corda.git
synced 2025-03-22 20:15:19 +00:00
Unit Tests for the amqp -> carpenter schema
Squahed commit mesages: * Better tests * WIP * WIP
This commit is contained in:
parent
4cbf31681b
commit
ce172887d0
@ -15,6 +15,8 @@ import java.lang.reflect.Type
|
|||||||
import java.lang.reflect.TypeVariable
|
import java.lang.reflect.TypeVariable
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
import net.corda.core.serialization.ClassCarpenterSchema
|
||||||
|
|
||||||
// TODO: get an assigned number as per AMQP spec
|
// TODO: get an assigned number as per AMQP spec
|
||||||
val DESCRIPTOR_TOP_32BITS: Long = 0xc0da0000
|
val DESCRIPTOR_TOP_32BITS: Long = 0xc0da0000
|
||||||
|
|
||||||
@ -87,9 +89,37 @@ data class Schema(val types: List<TypeNotation>) : DescribedType {
|
|||||||
override fun getDescribed(): Any = listOf(types)
|
override fun getDescribed(): Any = listOf(types)
|
||||||
|
|
||||||
override fun toString(): String = types.joinToString("\n")
|
override fun toString(): String = types.joinToString("\n")
|
||||||
|
|
||||||
|
fun carpenterSchema(loaders : List<ClassLoader> = listOf<ClassLoader>(ClassLoader.getSystemClassLoader()))
|
||||||
|
: List<ClassCarpenterSchema>
|
||||||
|
{
|
||||||
|
var rtn = mutableListOf<ClassCarpenterSchema>()
|
||||||
|
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rtn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Descriptor(val name: String?, val code: UnsignedLong? = null) : DescribedType {
|
data class Descriptor(var name: String?, val code: UnsignedLong? = null) : DescribedType {
|
||||||
companion object : DescribedTypeConstructor<Descriptor> {
|
companion object : DescribedTypeConstructor<Descriptor> {
|
||||||
val DESCRIPTOR = UnsignedLong(3L or DESCRIPTOR_TOP_32BITS)
|
val DESCRIPTOR = UnsignedLong(3L or DESCRIPTOR_TOP_32BITS)
|
||||||
|
|
||||||
@ -127,7 +157,7 @@ data class Descriptor(val name: String?, val code: UnsignedLong? = null) : Descr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Field(val name: String, val type: String, val requires: List<String>, val default: String?, val label: String?, val mandatory: Boolean, val multiple: Boolean) : DescribedType {
|
data class Field(var name: String, val type: String, val requires: List<String>, val default: String?, val label: String?, val mandatory: Boolean, val multiple: Boolean) : DescribedType {
|
||||||
companion object : DescribedTypeConstructor<Field> {
|
companion object : DescribedTypeConstructor<Field> {
|
||||||
val DESCRIPTOR = UnsignedLong(4L or DESCRIPTOR_TOP_32BITS)
|
val DESCRIPTOR = UnsignedLong(4L or DESCRIPTOR_TOP_32BITS)
|
||||||
|
|
||||||
@ -169,6 +199,16 @@ data class Field(val name: String, val type: String, val requires: List<String>,
|
|||||||
return sb.toString()
|
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 getPrimType() = when (type) {
|
||||||
"int" -> Int::class.javaPrimitiveType!!
|
"int" -> Int::class.javaPrimitiveType!!
|
||||||
"string" -> String::class.java
|
"string" -> String::class.java
|
||||||
@ -178,14 +218,8 @@ data class Field(val name: String, val type: String, val requires: List<String>,
|
|||||||
"boolean" -> Boolean::class.javaPrimitiveType!!
|
"boolean" -> Boolean::class.javaPrimitiveType!!
|
||||||
"double" -> Double::class.javaPrimitiveType!!
|
"double" -> Double::class.javaPrimitiveType!!
|
||||||
"float" -> Double::class.javaPrimitiveType!!
|
"float" -> Double::class.javaPrimitiveType!!
|
||||||
else -> {
|
"*" -> isKnownClass(requires[0])
|
||||||
try {
|
else -> isKnownClass(type)
|
||||||
ClassLoader.getSystemClassLoader().loadClass(type)
|
|
||||||
}
|
|
||||||
catch (e: ClassNotFoundException) {
|
|
||||||
throw IllegalArgumentException ("pants")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,13 +237,13 @@ sealed class TypeNotation : DescribedType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract val name: String
|
abstract var name: String
|
||||||
abstract val label: String?
|
abstract val label: String?
|
||||||
abstract val provides: List<String>
|
abstract val provides: List<String>
|
||||||
abstract val descriptor: Descriptor
|
abstract val descriptor: Descriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CompositeType(override val name: String, override val label: String?, override val provides: List<String>, override val descriptor: Descriptor, val fields: List<Field>) : TypeNotation() {
|
data class CompositeType(override var name: String, override val label: String?, override val provides: List<String>, override val descriptor: Descriptor, val fields: List<Field>) : TypeNotation() {
|
||||||
companion object : DescribedTypeConstructor<CompositeType> {
|
companion object : DescribedTypeConstructor<CompositeType> {
|
||||||
val DESCRIPTOR = UnsignedLong(5L or DESCRIPTOR_TOP_32BITS)
|
val DESCRIPTOR = UnsignedLong(5L or DESCRIPTOR_TOP_32BITS)
|
||||||
|
|
||||||
@ -253,16 +287,36 @@ data class CompositeType(override val name: String, override val label: String?,
|
|||||||
return sb.toString()
|
return sb.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun carpenterSchema() : Map<String, Class<out Any?>> {
|
fun carpenterSchema(classLoaders: List<ClassLoader> = listOf<ClassLoader> (ClassLoader.getSystemClassLoader())) : ClassCarpenterSchema {
|
||||||
var m : MutableMap<String, Class<out Any?>> = mutableMapOf()
|
var m : MutableMap<String, Class<out Any?>> = mutableMapOf()
|
||||||
|
|
||||||
fields.forEach { m[it.name] = it.getPrimType() }
|
fields.forEach { m[it.name] = it.getPrimType() }
|
||||||
|
|
||||||
return m
|
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}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClassCarpenterSchema (name, m, interfaces = providesList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
data class RestrictedType(override var name: String, override val label: String?, override val provides: List<String>, val source: String, override val descriptor: Descriptor, val choices: List<Choice>) : TypeNotation() {
|
||||||
companion object : DescribedTypeConstructor<RestrictedType> {
|
companion object : DescribedTypeConstructor<RestrictedType> {
|
||||||
val DESCRIPTOR = UnsignedLong(6L or DESCRIPTOR_TOP_32BITS)
|
val DESCRIPTOR = UnsignedLong(6L or DESCRIPTOR_TOP_32BITS)
|
||||||
|
|
||||||
@ -305,7 +359,7 @@ data class RestrictedType(override val name: String, override val label: String?
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Choice(val name: String, val value: String) : DescribedType {
|
data class Choice(var name: String, val value: String) : DescribedType {
|
||||||
companion object : DescribedTypeConstructor<Choice> {
|
companion object : DescribedTypeConstructor<Choice> {
|
||||||
val DESCRIPTOR = UnsignedLong(7L or DESCRIPTOR_TOP_32BITS)
|
val DESCRIPTOR = UnsignedLong(7L or DESCRIPTOR_TOP_32BITS)
|
||||||
|
|
||||||
|
@ -159,58 +159,18 @@ class ClassCarpenter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* A Schema represents a desired class.
|
|
||||||
*/
|
|
||||||
abstract class Schema(
|
|
||||||
val name: String,
|
|
||||||
fields: Map<String, Field>,
|
|
||||||
val superclass: Schema? = null,
|
|
||||||
val interfaces: List<Class<*>> = emptyList())
|
|
||||||
{
|
|
||||||
private fun Map<String, ClassCarpenter.Field>.descriptors() =
|
|
||||||
LinkedHashMap(this.mapValues { it.value.descriptor })
|
|
||||||
|
|
||||||
/* Fix the order up front if the user didn't, inject the name into the field as it's
|
|
||||||
neater when iterating */
|
|
||||||
val fields = LinkedHashMap(fields.mapValues { it.value.copy(it.key, it.value.field) })
|
|
||||||
|
|
||||||
fun fieldsIncludingSuperclasses(): Map<String, Field> =
|
|
||||||
(superclass?.fieldsIncludingSuperclasses() ?: emptyMap()) + LinkedHashMap(fields)
|
|
||||||
|
|
||||||
fun descriptorsIncludingSuperclasses(): Map<String, String> =
|
|
||||||
(superclass?.descriptorsIncludingSuperclasses() ?: emptyMap()) + fields.descriptors()
|
|
||||||
|
|
||||||
val jvmName: String
|
|
||||||
get() = name.replace(".", "/")
|
|
||||||
}
|
|
||||||
|
|
||||||
private val String.jvm: String get() = replace(".", "/")
|
|
||||||
|
|
||||||
class ClassSchema(
|
|
||||||
name: String,
|
|
||||||
fields: Map<String, Field>,
|
|
||||||
superclass: Schema? = null,
|
|
||||||
interfaces: List<Class<*>> = emptyList()
|
|
||||||
) : Schema(name, fields, superclass, interfaces)
|
|
||||||
|
|
||||||
class InterfaceSchema(
|
|
||||||
name: String,
|
|
||||||
fields: Map<String, Field>,
|
|
||||||
superclass: Schema? = null,
|
|
||||||
interfaces: List<Class<*>> = emptyList()
|
|
||||||
) : Schema(name, fields, superclass, interfaces)
|
|
||||||
|
|
||||||
private class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoader) {
|
private class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoader) {
|
||||||
fun load(name: String, bytes: ByteArray) = defineClass(name, bytes, 0, bytes.size)
|
fun load(name: String, bytes: ByteArray) = defineClass(name, bytes, 0, bytes.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val classloader = CarpenterClassLoader()
|
private val classloader = CarpenterClassLoader()
|
||||||
|
|
||||||
|
fun classLoader() = classloader as ClassLoader
|
||||||
|
|
||||||
private val _loaded = HashMap<String, Class<*>>()
|
private val _loaded = HashMap<String, Class<*>>()
|
||||||
|
|
||||||
/** Returns a snapshot of the currently loaded classes as a map of full class name (package names+dots) -> class object */
|
/** Returns a snapshot of the currently loaded classes as a map of full class name (package names+dots) -> class object */
|
||||||
val loaded: Map<String, Class<*>> = HashMap(_loaded)
|
fun 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
|
* Generate bytecode for the given schema and load into the JVM. The returned class object can be used to
|
||||||
@ -218,18 +178,17 @@ 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)
|
* @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<*> {
|
fun build(schema: ClassCarpenterSchema): Class<*> {
|
||||||
validateSchema(schema)
|
validateSchema(schema)
|
||||||
// Walk up the inheritance hierarchy and then start walking back down once we either hit the top, or
|
// 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.
|
// find a class we haven't generated yet.
|
||||||
val hierarchy = ArrayList<Schema>()
|
val hierarchy = ArrayList<ClassCarpenterSchema>()
|
||||||
hierarchy += schema
|
hierarchy += schema
|
||||||
var cursor = schema.superclass
|
var cursor = schema.superclass
|
||||||
while (cursor != null && cursor.name !in _loaded) {
|
while (cursor != null && cursor.name !in _loaded) {
|
||||||
hierarchy += cursor
|
hierarchy += cursor
|
||||||
cursor = cursor.superclass
|
cursor = cursor.superclass
|
||||||
}
|
}
|
||||||
|
|
||||||
hierarchy.reversed().forEach {
|
hierarchy.reversed().forEach {
|
||||||
when (it) {
|
when (it) {
|
||||||
is InterfaceSchema -> generateInterface(it)
|
is InterfaceSchema -> generateInterface(it)
|
||||||
@ -346,6 +305,7 @@ class ClassCarpenter {
|
|||||||
visitEnd()
|
visitEnd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ClassWriter.generateAbstractGetters(schema: Schema) {
|
private fun ClassWriter.generateAbstractGetters(schema: Schema) {
|
||||||
@ -374,14 +334,16 @@ class ClassCarpenter {
|
|||||||
// Calculate the super call.
|
// Calculate the super call.
|
||||||
val superclassFields = schema.superclass?.fieldsIncludingSuperclasses() ?: emptyMap()
|
val superclassFields = schema.superclass?.fieldsIncludingSuperclasses() ?: emptyMap()
|
||||||
visitVarInsn(ALOAD, 0)
|
visitVarInsn(ALOAD, 0)
|
||||||
if (schema.superclass == null) {
|
val sc = schema.superclass
|
||||||
|
if (sc == null) {
|
||||||
visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
|
visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false)
|
||||||
} else {
|
} else {
|
||||||
var slot = 1
|
var slot = 1
|
||||||
for (fieldType in superclassFields.values)
|
for (fieldType in superclassFields.values)
|
||||||
slot += load(slot, fieldType)
|
slot += load(slot, fieldType)
|
||||||
val superDesc = schema.superclass.descriptorsIncludingSuperclasses().values.joinToString("")
|
//val superDesc = schema.superclass.descriptorsIncludingSuperclasses().values.joinToString("")
|
||||||
visitMethodInsn(INVOKESPECIAL, schema.superclass.name.jvm, "<init>", "($superDesc)V", false)
|
val superDesc = sc.descriptorsIncludingSuperclasses().values.joinToString("")
|
||||||
|
visitMethodInsn(INVOKESPECIAL, sc.name.jvm, "<init>", "($superDesc)V", false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign the fields from parameters.
|
// Assign the fields from parameters.
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
package net.corda.core.serialization.carpenter
|
||||||
|
|
||||||
|
import org.objectweb.asm.Type
|
||||||
|
import java.util.LinkedHashMap
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Schema represents a desired class.
|
||||||
|
*/
|
||||||
|
abstract class Schema(
|
||||||
|
val name: String,
|
||||||
|
fields: Map<String, Field>,
|
||||||
|
val superclass: Schema? = null,
|
||||||
|
val interfaces: List<Class<*>> = emptyList())
|
||||||
|
{
|
||||||
|
private fun Map<String, ClassCarpenter.Field>.descriptors() =
|
||||||
|
LinkedHashMap(this.mapValues { it.value.descriptor })
|
||||||
|
|
||||||
|
/* Fix the order up front if the user didn't, inject the name into the field as it's
|
||||||
|
neater when iterating */
|
||||||
|
val fields = LinkedHashMap(fields.mapValues { it.value.copy(it.key, it.value.field) })
|
||||||
|
|
||||||
|
fun fieldsIncludingSuperclasses(): Map<String, Field> =
|
||||||
|
(superclass?.fieldsIncludingSuperclasses() ?: emptyMap()) + LinkedHashMap(fields)
|
||||||
|
|
||||||
|
fun descriptorsIncludingSuperclasses(): Map<String, String> =
|
||||||
|
(superclass?.descriptorsIncludingSuperclasses() ?: emptyMap()) + fields.descriptors()
|
||||||
|
|
||||||
|
val jvmName: String
|
||||||
|
get() = name.replace(".", "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClassSchema(
|
||||||
|
name: String,
|
||||||
|
fields: Map<String, Class<out Any?>>,
|
||||||
|
superclass: Schema? = null,
|
||||||
|
interfaces: List<Class<*>> = emptyList()
|
||||||
|
) : ClassCarpenter.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)
|
@ -8,11 +8,31 @@ import java.beans.Introspector
|
|||||||
import kotlin.test.assertNotEquals
|
import kotlin.test.assertNotEquals
|
||||||
|
|
||||||
class ClassCarpenterTest {
|
class ClassCarpenterTest {
|
||||||
|
/*
|
||||||
|
cw.visitInnerClass(
|
||||||
|
"net/corda/carpenter/ClassCarpenterTest$DummyInterface",
|
||||||
|
"net/corda/carpenter/ClassCarpenterTest",
|
||||||
|
"DummyInterface",
|
||||||
|
ACC_PUBLIC + ACC_STATIC + ACC_ABSTRACT + ACC_INTERFACE);
|
||||||
|
*/
|
||||||
interface DummyInterface {
|
interface DummyInterface {
|
||||||
val a: String
|
val a: String
|
||||||
val b: Int
|
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()
|
val cc = ClassCarpenter()
|
||||||
|
|
||||||
// We have to ignore synthetic fields even though ClassCarpenter doesn't create any because the JaCoCo
|
// We have to ignore synthetic fields even though ClassCarpenter doesn't create any because the JaCoCo
|
||||||
@ -22,7 +42,7 @@ class ClassCarpenterTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun empty() {
|
fun empty() {
|
||||||
val clazz = cc.build(ClassCarpenter.ClassSchema("gen.EmptyClass", emptyMap(), null))
|
val clazz = cc.build(ClassSchema("gen.EmptyClass", emptyMap(), null))
|
||||||
assertEquals(0, clazz.nonSyntheticFields.size)
|
assertEquals(0, clazz.nonSyntheticFields.size)
|
||||||
assertEquals(2, clazz.nonSyntheticMethods.size) // get, toString
|
assertEquals(2, clazz.nonSyntheticMethods.size) // get, toString
|
||||||
assertEquals(0, clazz.declaredConstructors[0].parameterCount)
|
assertEquals(0, clazz.declaredConstructors[0].parameterCount)
|
||||||
@ -69,7 +89,7 @@ class ClassCarpenterTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun genPerson(): Pair<Class<*>, Any> {
|
private fun genPerson(): Pair<Class<*>, Any> {
|
||||||
val clazz = cc.build(ClassCarpenter.ClassSchema("gen.Person", mapOf(
|
val clazz = cc.build(ClassSchema("gen.Person", mapOf(
|
||||||
"age" to Int::class.javaPrimitiveType!!,
|
"age" to Int::class.javaPrimitiveType!!,
|
||||||
"name" to String::class.java
|
"name" to String::class.java
|
||||||
).mapValues { ClassCarpenter.NonNullableField (it.value) } ))
|
).mapValues { ClassCarpenter.NonNullableField (it.value) } ))
|
||||||
@ -92,8 +112,8 @@ class ClassCarpenterTest {
|
|||||||
|
|
||||||
@Test(expected = ClassCarpenter.DuplicateNameException::class)
|
@Test(expected = ClassCarpenter.DuplicateNameException::class)
|
||||||
fun duplicates() {
|
fun duplicates() {
|
||||||
cc.build(ClassCarpenter.ClassSchema("gen.EmptyClass", emptyMap(), null))
|
cc.build(ClassSchema("gen.EmptyClass", emptyMap(), null))
|
||||||
cc.build(ClassCarpenter.ClassSchema("gen.EmptyClass", emptyMap(), null))
|
cc.build(ClassSchema("gen.EmptyClass", emptyMap(), null))
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -134,6 +154,7 @@ class ClassCarpenterTest {
|
|||||||
mapOf("b" to ClassCarpenter.NonNullableField(Int::class.java)),
|
mapOf("b" to ClassCarpenter.NonNullableField(Int::class.java)),
|
||||||
schema1,
|
schema1,
|
||||||
interfaces = listOf(DummyInterface::class.java))
|
interfaces = listOf(DummyInterface::class.java))
|
||||||
|
|
||||||
val clazz = cc.build(schema2)
|
val clazz = cc.build(schema2)
|
||||||
val i = clazz.constructors[0].newInstance("xa", 1) as DummyInterface
|
val i = clazz.constructors[0].newInstance("xa", 1) as DummyInterface
|
||||||
assertEquals("xa", i.a)
|
assertEquals("xa", i.a)
|
||||||
|
@ -1,263 +0,0 @@
|
|||||||
package net.corda.carpenter
|
|
||||||
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
|
||||||
import net.corda.core.serialization.amqp.*
|
|
||||||
import org.junit.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
|
|
||||||
class ClassCarpenterScehmaTestsSingleMemberComposite {
|
|
||||||
private var factory = SerializerFactory()
|
|
||||||
|
|
||||||
fun serialise (clazz : Any) = SerializationOutput(factory).serialize(clazz)
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun singleInteger() {
|
|
||||||
val test = 10
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : Int)
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
|
||||||
|
|
||||||
assertEquals (1, amqpSchema.fields.size)
|
|
||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
|
||||||
assertEquals ("int", amqpSchema.fields[0].type)
|
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun singleString() {
|
|
||||||
val test = "ten"
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : String)
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var 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)
|
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@Test
|
|
||||||
fun singleChar () {
|
|
||||||
val test = 'c'
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : Char)
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var 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 p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun singleLong() {
|
|
||||||
val test = 10L
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : Long)
|
|
||||||
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
|
||||||
|
|
||||||
assertEquals (1, amqpSchema.fields.size)
|
|
||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
|
||||||
assertEquals ("long", amqpSchema.fields[0].type)
|
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun singleShort() {
|
|
||||||
val test = 10.toShort()
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : Short)
|
|
||||||
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
|
||||||
|
|
||||||
assertEquals (1, amqpSchema.fields.size)
|
|
||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
|
||||||
assertEquals ("short", amqpSchema.fields[0].type)
|
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@Test
|
|
||||||
fun singleBool() {
|
|
||||||
val test = true
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : Boolean)
|
|
||||||
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var amqpSchema = obj.second.schema.types[0] as CompositeType
|
|
||||||
|
|
||||||
assertEquals (1, amqpSchema.fields.size)
|
|
||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
|
||||||
assertEquals ("boolean", amqpSchema.fields[0].type)
|
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun singleDouble() {
|
|
||||||
val test = 10.0
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : Double)
|
|
||||||
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var 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(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun singleFloat() {
|
|
||||||
val test = 10.0F
|
|
||||||
|
|
||||||
@CordaSerializable
|
|
||||||
data class A(val a : Float)
|
|
||||||
|
|
||||||
var a = A (test)
|
|
||||||
|
|
||||||
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise (a))
|
|
||||||
|
|
||||||
assert (obj.first is A)
|
|
||||||
val amqpObj = obj.first as A
|
|
||||||
|
|
||||||
assertEquals (test, amqpObj.a)
|
|
||||||
assertEquals (1, obj.second.schema.types.size)
|
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
|
||||||
|
|
||||||
var 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(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
|
||||||
|
|
||||||
// assertEquals (pinochio.getMethod("getA").invoke (p), amqpObj.a)
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,10 +2,11 @@ package net.corda.carpenter
|
|||||||
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
import net.corda.core.serialization.amqp.*
|
import net.corda.core.serialization.amqp.*
|
||||||
|
import net.corda.core.serialization.ClassCarpenterSchema
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class CompositeMemberCompositeSchemaToClassCarpenterTests {
|
class Inheritance {
|
||||||
private var factory = SerializerFactory()
|
private var factory = SerializerFactory()
|
||||||
|
|
||||||
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
fun serialise(clazz: Any) = SerializationOutput(factory).serialize(clazz)
|
||||||
@ -35,6 +36,9 @@ class CompositeMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assert(obj.second.schema.types[0] is CompositeType)
|
assert(obj.second.schema.types[0] is CompositeType)
|
||||||
assert(obj.second.schema.types[1] 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 amqpSchemaA : CompositeType? = null
|
||||||
var amqpSchemaB : CompositeType? = null
|
var amqpSchemaB : CompositeType? = null
|
||||||
|
|
||||||
@ -52,15 +56,15 @@ class CompositeMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals("a", amqpSchemaA!!.fields[0].name)
|
assertEquals("a", amqpSchemaA!!.fields[0].name)
|
||||||
assertEquals("int", amqpSchemaA!!.fields[0].type)
|
assertEquals("int", amqpSchemaA!!.fields[0].type)
|
||||||
|
|
||||||
|
|
||||||
assertEquals(2, amqpSchemaB?.fields?.size)
|
assertEquals(2, amqpSchemaB?.fields?.size)
|
||||||
assertEquals("a", amqpSchemaB!!.fields[0].name)
|
assertEquals("a", amqpSchemaB!!.fields[0].name)
|
||||||
assertEquals("net.corda.carpenter.CompositeMemberCompositeSchemaToClassCarpenterTests\$nestedInts\$A",
|
assertEquals("${this.javaClass.name}\$nestedInts\$A", amqpSchemaB!!.fields[0].type)
|
||||||
amqpSchemaB!!.fields[0].type)
|
|
||||||
assertEquals("b", amqpSchemaB!!.fields[1].name)
|
assertEquals("b", amqpSchemaB!!.fields[1].name)
|
||||||
assertEquals("int", amqpSchemaB!!.fields[1].type)
|
assertEquals("int", amqpSchemaB!!.fields[1].type)
|
||||||
|
|
||||||
var ccA = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchemaA.name, amqpSchemaA.carpenterSchema()))
|
var ccA = ClassCarpenter().build(amqpSchemaA.carpenterSchema())
|
||||||
var ccB = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchemaB.name, amqpSchemaB.carpenterSchema()))
|
var ccB = ClassCarpenter().build(amqpSchemaB.carpenterSchema())
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since A is known to the JVM we can't constuct B with and instance of the carpented A but
|
* Since A is known to the JVM we can't constuct B with and instance of the carpented A but
|
||||||
@ -72,7 +76,7 @@ class CompositeMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals (ccA.getMethod("getA").invoke(instanceA), amqpObj.a.a)
|
assertEquals (ccA.getMethod("getA").invoke(instanceA), amqpObj.a.a)
|
||||||
assertEquals ((ccB.getMethod("getA").invoke(instanceB) as A).a, amqpObj.a.a)
|
assertEquals ((ccB.getMethod("getA").invoke(instanceB) as A).a, amqpObj.a.a)
|
||||||
assertEquals (ccB.getMethod("getB").invoke(instanceB), amqpObj.b)
|
assertEquals (ccB.getMethod("getB").invoke(instanceB), amqpObj.b)
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,389 @@
|
|||||||
|
package net.corda.carpenter
|
||||||
|
|
||||||
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
import net.corda.core.serialization.amqp.*
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
/*******************************************************************************************************/
|
||||||
|
|
||||||
|
@CordaSerializable
|
||||||
|
interface J {
|
||||||
|
val j : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************************************/
|
||||||
|
|
||||||
|
@CordaSerializable
|
||||||
|
interface I {
|
||||||
|
val i : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
@CordaSerializable
|
||||||
|
interface II {
|
||||||
|
val ii : Int
|
||||||
|
}
|
||||||
|
|
||||||
|
@CordaSerializable
|
||||||
|
interface III : I {
|
||||||
|
val iii : Int
|
||||||
|
override val i: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
@CordaSerializable
|
||||||
|
interface IIII {
|
||||||
|
val iiii : Int
|
||||||
|
val i : I
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************************************/
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun interfaceParent1() {
|
||||||
|
val testJ = 20
|
||||||
|
val testName = "interfaceParent1"
|
||||||
|
|
||||||
|
class A(override val j: Int) : J
|
||||||
|
|
||||||
|
val a = A(testJ)
|
||||||
|
|
||||||
|
assertEquals(testJ, a.j)
|
||||||
|
|
||||||
|
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||||
|
|
||||||
|
assert(obj.first is A)
|
||||||
|
|
||||||
|
val serSchema = obj.second.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 */
|
||||||
|
assertEquals(0, l1.size)
|
||||||
|
|
||||||
|
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$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 aBuilder = ClassCarpenter().build(l2[0])
|
||||||
|
|
||||||
|
val objJ = aBuilder.constructors[0].newInstance(testJ)
|
||||||
|
val j = objJ as J
|
||||||
|
|
||||||
|
assertEquals(aBuilder.getMethod("getJ").invoke(objJ), testJ)
|
||||||
|
assertEquals(a.j, j.j)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun interfaceParent2() {
|
||||||
|
val testJ = 20
|
||||||
|
val testJJ = 40
|
||||||
|
val testName = "interfaceParent2"
|
||||||
|
|
||||||
|
class A(override val j: Int, val jj: Int) : J
|
||||||
|
|
||||||
|
val a = A(testJ, testJJ)
|
||||||
|
|
||||||
|
assertEquals(testJ, a.j)
|
||||||
|
assertEquals(testJJ, a.jj)
|
||||||
|
|
||||||
|
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||||
|
|
||||||
|
assert(obj.first is A)
|
||||||
|
|
||||||
|
val serSchema = obj.second.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 */
|
||||||
|
assertEquals(0, l1.size)
|
||||||
|
|
||||||
|
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$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 aBuilder = ClassCarpenter().build(l2[0])
|
||||||
|
|
||||||
|
val objJ = aBuilder.constructors[0].newInstance(testJ, testJJ)
|
||||||
|
val j = objJ as J
|
||||||
|
|
||||||
|
assertEquals(aBuilder.getMethod("getJ").invoke(objJ), testJ)
|
||||||
|
assertEquals(aBuilder.getMethod("getJj").invoke(objJ), testJJ)
|
||||||
|
|
||||||
|
assertEquals(a.j, j.j)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun multipleInterfaces() {
|
||||||
|
val testI = 20
|
||||||
|
val testII = 40
|
||||||
|
val testName = "multipleInterfaces"
|
||||||
|
|
||||||
|
class A(override val i: Int, override val ii: Int) : I, II
|
||||||
|
|
||||||
|
val a = A(testI, testII)
|
||||||
|
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||||
|
|
||||||
|
assert(obj.first is A)
|
||||||
|
|
||||||
|
val serSchema = obj.second.schema
|
||||||
|
|
||||||
|
assertEquals(3, 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 */
|
||||||
|
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 curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A"))
|
||||||
|
val l2 = curruptSchema.carpenterSchema()
|
||||||
|
|
||||||
|
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 aBuilder = ClassCarpenter().build(l2[0])
|
||||||
|
|
||||||
|
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
|
||||||
|
val testName = "nestedInterfaces"
|
||||||
|
|
||||||
|
class A(override val i: Int, override val iii : Int) : III
|
||||||
|
|
||||||
|
val a = A(testI, testIII)
|
||||||
|
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(a))
|
||||||
|
|
||||||
|
assert(obj.first is A)
|
||||||
|
|
||||||
|
val serSchema = obj.second.schema
|
||||||
|
|
||||||
|
assertEquals(3, 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 */
|
||||||
|
assertEquals(0, l1.size)
|
||||||
|
|
||||||
|
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A"))
|
||||||
|
val l2 = curruptSchema.carpenterSchema()
|
||||||
|
|
||||||
|
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 aBuilder = ClassCarpenter().build(l2[0])
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
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
|
||||||
|
|
||||||
|
val a = A(testI)
|
||||||
|
val b = B(a, testIIII)
|
||||||
|
|
||||||
|
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||||
|
|
||||||
|
assert(obj.first is B)
|
||||||
|
|
||||||
|
val serSchema = obj.second.schema
|
||||||
|
|
||||||
|
/*
|
||||||
|
* class A
|
||||||
|
* class A's interface (class I)
|
||||||
|
* class B
|
||||||
|
* class B's interface (class IIII)
|
||||||
|
*/
|
||||||
|
assertEquals(4, serSchema.types.size)
|
||||||
|
|
||||||
|
val curruptSchema = curruptName (serSchema, listOf ("${this.javaClass.name}\$$testName\$A",
|
||||||
|
"${this.javaClass.name}\$$testName\$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") }
|
||||||
|
|
||||||
|
assert(aCarpenterSchema != null)
|
||||||
|
assert(bCarpenterSchema != null)
|
||||||
|
|
||||||
|
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 */
|
||||||
|
bBuilder.constructors[0].newInstance(objA, testIIII)
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this time remove the nested interface from out set of known classes forcing us
|
||||||
|
to whittle it */
|
||||||
|
@Test
|
||||||
|
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
|
||||||
|
|
||||||
|
val a = A(testI)
|
||||||
|
val b = B(a, testIIII)
|
||||||
|
|
||||||
|
val obj = DeserializationInput(factory).deserializeRtnEnvelope(serialise(b))
|
||||||
|
|
||||||
|
assert(obj.first is B)
|
||||||
|
|
||||||
|
val serSchema = obj.second.schema
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
|
||||||
|
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)
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ class MultiMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals("b", amqpSchema.fields[1].name)
|
assertEquals("b", amqpSchema.fields[1].name)
|
||||||
assertEquals("int", amqpSchema.fields[1].type)
|
assertEquals("int", amqpSchema.fields[1].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance(testA, testB)
|
val p = pinochio.constructors[0].newInstance(testA, testB)
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ class MultiMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals("b", amqpSchema.fields[1].name)
|
assertEquals("b", amqpSchema.fields[1].name)
|
||||||
assertEquals("string", amqpSchema.fields[1].type)
|
assertEquals("string", amqpSchema.fields[1].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance(testA, testB)
|
val p = pinochio.constructors[0].newInstance(testA, testB)
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package net.corda.carpenter
|
package net.corda.carpenter
|
||||||
|
|
||||||
import net.corda.core.serialization.CordaSerializable
|
import net.corda.core.serialization.CordaSerializable
|
||||||
|
import net.corda.core.serialization.ClassCarpenterSchema
|
||||||
import net.corda.core.serialization.amqp.*
|
import net.corda.core.serialization.amqp.*
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@ -17,8 +18,8 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
|
|
||||||
@CordaSerializable
|
@CordaSerializable
|
||||||
data class A(val a : Int)
|
data class A(val a : Int)
|
||||||
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)
|
assert (obj.first is A)
|
||||||
@ -28,13 +29,13 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals (1, obj.second.schema.types.size)
|
assertEquals (1, obj.second.schema.types.size)
|
||||||
assert (obj.second.schema.types[0] is CompositeType)
|
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 (1, amqpSchema.fields.size)
|
||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
assertEquals ("a", amqpSchema.fields[0].name)
|
||||||
assertEquals ("int", amqpSchema.fields[0].type)
|
assertEquals ("int", amqpSchema.fields[0].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
val pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
val p = pinochio.constructors[0].newInstance (test)
|
||||||
|
|
||||||
@ -64,7 +65,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
assertEquals ("a", amqpSchema.fields[0].name)
|
||||||
assertEquals ("string", amqpSchema.fields[0].type)
|
assertEquals ("string", amqpSchema.fields[0].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
val p = pinochio.constructors[0].newInstance (test)
|
||||||
|
|
||||||
@ -128,7 +129,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
assertEquals ("a", amqpSchema.fields[0].name)
|
||||||
assertEquals ("long", amqpSchema.fields[0].type)
|
assertEquals ("long", amqpSchema.fields[0].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
val p = pinochio.constructors[0].newInstance (test)
|
||||||
|
|
||||||
@ -159,7 +160,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
assertEquals ("a", amqpSchema.fields[0].name)
|
||||||
assertEquals ("short", amqpSchema.fields[0].type)
|
assertEquals ("short", amqpSchema.fields[0].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
val p = pinochio.constructors[0].newInstance (test)
|
||||||
|
|
||||||
@ -223,7 +224,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
assertEquals ("a", amqpSchema.fields[0].name)
|
||||||
assertEquals ("double", amqpSchema.fields[0].type)
|
assertEquals ("double", amqpSchema.fields[0].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
val p = pinochio.constructors[0].newInstance (test)
|
||||||
|
|
||||||
@ -254,7 +255,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests {
|
|||||||
assertEquals ("a", amqpSchema.fields[0].name)
|
assertEquals ("a", amqpSchema.fields[0].name)
|
||||||
assertEquals ("float", amqpSchema.fields[0].type)
|
assertEquals ("float", amqpSchema.fields[0].type)
|
||||||
|
|
||||||
var pinochio = ClassCarpenter().build(ClassCarpenter.Schema(amqpSchema.name, amqpSchema.carpenterSchema()))
|
var pinochio = ClassCarpenter().build(amqpSchema.carpenterSchema())
|
||||||
|
|
||||||
val p = pinochio.constructors[0].newInstance (test)
|
val p = pinochio.constructors[0].newInstance (test)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user