mirror of
https://github.com/corda/corda.git
synced 2025-02-21 01:42:24 +00:00
Update to account for nullability awareness in the carpenter
This commit is contained in:
parent
c29673a4a4
commit
5ab26dd275
@ -17,7 +17,9 @@ import java.util.*
|
||||
|
||||
import net.corda.core.serialization.carpenter.CarpenterSchemas
|
||||
import net.corda.core.serialization.carpenter.Schema as CarpenterSchema
|
||||
import net.corda.core.serialization.carpenter.Field as CarpenterField
|
||||
import net.corda.core.serialization.carpenter.CarpenterSchemaFactory
|
||||
import net.corda.core.serialization.carpenter.FieldFactory
|
||||
|
||||
// TODO: get an assigned number as per AMQP spec
|
||||
val DESCRIPTOR_TOP_32BITS: Long = 0xc0da0000
|
||||
@ -350,11 +352,11 @@ data class CompositeType(override val name: String, override val label: String?,
|
||||
}
|
||||
}
|
||||
|
||||
val m : MutableMap<String, Class<out Any?>> = mutableMapOf()
|
||||
val m : MutableMap<String, CarpenterField> = mutableMapOf()
|
||||
|
||||
fields.forEach {
|
||||
try {
|
||||
m[it.name] = it.getTypeAsClass(classLoaders)
|
||||
m[it.name] = FieldFactory.newInstance(it.mandatory, it.name, it.getTypeAsClass(classLoaders))
|
||||
}
|
||||
catch (e: ClassNotFoundException) {
|
||||
carpenterSchemas.addDepPair(this, name, it.typeAsString())
|
||||
|
@ -3,17 +3,14 @@ package net.corda.core.serialization.carpenter
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.MethodVisitor
|
||||
import org.objectweb.asm.Opcodes.*
|
||||
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.*
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
/**
|
||||
* Any object that implements this interface is expected to expose its own fields via the [get] method, exactly
|
||||
* as if `this.class.getMethod("get" + name.capitalize()).invoke(this)` had been called. It is intended as a more
|
||||
@ -23,6 +20,13 @@ interface SimpleFieldAccess {
|
||||
operator fun get(name: String): Any?
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
class CarpenterClassLoader : ClassLoader(Thread.currentThread().contextClassLoader) {
|
||||
fun load(name: String, bytes: ByteArray) = defineClass(name, bytes, 0, bytes.size)
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
/**
|
||||
* A class carpenter generates JVM bytecodes for a class given a schema and then loads it into a sub-classloader.
|
||||
@ -68,15 +72,6 @@ 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.
|
||||
@ -84,94 +79,6 @@ class ClassCarpenter {
|
||||
// TODO: Support annotations.
|
||||
// TODO: isFoo getter patterns for booleans (this is what Kotlin generates)
|
||||
|
||||
class DuplicateNameException : RuntimeException("An attempt was made to register two classes with the same name within the same ClassCarpenter namespace.")
|
||||
class InterfaceMismatchException(msg: String) : RuntimeException(msg)
|
||||
class NullablePrimitiveException(msg: String) : RuntimeException(msg)
|
||||
|
||||
abstract class Field(val field: Class<out Any?>) {
|
||||
companion object {
|
||||
const val unsetName = "Unset"
|
||||
}
|
||||
|
||||
var name: String = unsetName
|
||||
abstract val nullabilityAnnotation: String
|
||||
|
||||
val descriptor: String
|
||||
get() = Type.getDescriptor(this.field)
|
||||
|
||||
val type: String
|
||||
get() = if (this.field.isPrimitive) this.descriptor else "Ljava/lang/Object;"
|
||||
|
||||
fun generateField(cw: ClassWriter) {
|
||||
val fieldVisitor = cw.visitField(ACC_PROTECTED + ACC_FINAL, name, descriptor, null, null)
|
||||
fieldVisitor.visitAnnotation(nullabilityAnnotation, true).visitEnd()
|
||||
fieldVisitor.visitEnd()
|
||||
}
|
||||
|
||||
fun addNullabilityAnnotation(mv: MethodVisitor) {
|
||||
mv.visitAnnotation(nullabilityAnnotation, true).visitEnd()
|
||||
}
|
||||
|
||||
fun visitParameter(mv: MethodVisitor, idx: Int) {
|
||||
with(mv) {
|
||||
visitParameter(name, 0)
|
||||
if (!field.isPrimitive) {
|
||||
visitParameterAnnotation(idx, nullabilityAnnotation, true).visitEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun copy(name: String, field: Class<out Any?>): Field
|
||||
abstract fun nullTest(mv: MethodVisitor, slot: Int)
|
||||
}
|
||||
|
||||
class NonNullableField(field: Class<out Any?>) : Field(field) {
|
||||
override val nullabilityAnnotation = "Ljavax/annotation/Nonnull;"
|
||||
|
||||
constructor(name: String, field: Class<out Any?>) : this(field) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
override fun copy(name: String, field: Class<out Any?>) = NonNullableField(name, field)
|
||||
|
||||
override fun nullTest(mv: MethodVisitor, slot: Int) {
|
||||
assert(name != unsetName)
|
||||
|
||||
if (!field.isPrimitive) {
|
||||
with(mv) {
|
||||
visitVarInsn(ALOAD, 0) // load this
|
||||
visitVarInsn(ALOAD, slot) // load parameter
|
||||
visitLdcInsn("param \"$name\" cannot be null")
|
||||
visitMethodInsn(INVOKESTATIC,
|
||||
"java/util/Objects",
|
||||
"requireNonNull",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false)
|
||||
visitInsn(POP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class NullableField(field: Class<out Any?>) : Field(field) {
|
||||
override val nullabilityAnnotation = "Ljavax/annotation/Nullable;"
|
||||
|
||||
constructor(name: String, field: Class<out Any?>) : this(field) {
|
||||
if (field.isPrimitive) {
|
||||
throw NullablePrimitiveException (
|
||||
"Field $name is primitive type ${Type.getDescriptor(field)} and thus cannot be nullable")
|
||||
}
|
||||
|
||||
this.name = name
|
||||
}
|
||||
|
||||
override fun copy(name: String, field: Class<out Any?>) = NullableField(name, field)
|
||||
|
||||
override fun nullTest(mv: MethodVisitor, slot: Int) {
|
||||
assert(name != unsetName)
|
||||
}
|
||||
}
|
||||
|
||||
val classloader = CarpenterClassLoader()
|
||||
|
||||
private val _loaded = HashMap<String, Class<*>>()
|
||||
|
@ -0,0 +1,9 @@
|
||||
package net.corda.core.serialization.carpenter
|
||||
|
||||
|
||||
class DuplicateNameException : RuntimeException (
|
||||
"An attempt was made to register two classes with the same name within the same ClassCarpenter namespace.")
|
||||
|
||||
class InterfaceMismatchException(msg: String) : RuntimeException(msg)
|
||||
|
||||
class NullablePrimitiveException(msg: String) : RuntimeException(msg)
|
@ -1,5 +1,10 @@
|
||||
package net.corda.core.serialization.carpenter
|
||||
|
||||
import jdk.internal.org.objectweb.asm.Opcodes.*
|
||||
|
||||
import org.objectweb.asm.ClassWriter
|
||||
import org.objectweb.asm.MethodVisitor
|
||||
|
||||
import org.objectweb.asm.Type
|
||||
import java.util.LinkedHashMap
|
||||
|
||||
@ -14,7 +19,7 @@ abstract class Schema(
|
||||
val superclass: Schema? = null,
|
||||
val interfaces: List<Class<*>> = emptyList())
|
||||
{
|
||||
private fun Map<String, ClassCarpenter.Field>.descriptors() =
|
||||
private fun Map<String, 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
|
||||
@ -35,7 +40,7 @@ abstract class Schema(
|
||||
|
||||
class ClassSchema(
|
||||
name: String,
|
||||
fields: Map<String, Class<out Any?>>,
|
||||
fields: Map<String, Field>,
|
||||
superclass: Schema? = null,
|
||||
interfaces: List<Class<*>> = emptyList()
|
||||
) : Schema (name, fields, superclass, interfaces)
|
||||
@ -44,7 +49,7 @@ class ClassSchema(
|
||||
|
||||
class InterfaceSchema(
|
||||
name: String,
|
||||
fields: Map<String, Class<out Any?>>,
|
||||
fields: Map<String, Field>,
|
||||
superclass: Schema? = null,
|
||||
interfaces: List<Class<*>> = emptyList()
|
||||
) : Schema (name, fields, superclass, interfaces)
|
||||
@ -54,7 +59,7 @@ class InterfaceSchema(
|
||||
object CarpenterSchemaFactory {
|
||||
fun newInstance (
|
||||
name: String,
|
||||
fields: Map<String, Class<out Any?>>,
|
||||
fields: Map<String, Field>,
|
||||
superclass: Schema? = null,
|
||||
interfaces: List<Class<*>> = emptyList(),
|
||||
isInterface: Boolean = false
|
||||
@ -64,3 +69,100 @@ object CarpenterSchemaFactory {
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
abstract class Field(val field: Class<out Any?>) {
|
||||
companion object {
|
||||
const val unsetName = "Unset"
|
||||
}
|
||||
|
||||
var name: String = unsetName
|
||||
abstract val nullabilityAnnotation: String
|
||||
|
||||
val descriptor: String
|
||||
get() = Type.getDescriptor(this.field)
|
||||
|
||||
val type: String
|
||||
get() = if (this.field.isPrimitive) this.descriptor else "Ljava/lang/Object;"
|
||||
|
||||
fun generateField(cw: ClassWriter) {
|
||||
val fieldVisitor = cw.visitField(ACC_PROTECTED + ACC_FINAL, name, descriptor, null, null)
|
||||
fieldVisitor.visitAnnotation(nullabilityAnnotation, true).visitEnd()
|
||||
fieldVisitor.visitEnd()
|
||||
}
|
||||
|
||||
fun addNullabilityAnnotation(mv: MethodVisitor) {
|
||||
mv.visitAnnotation(nullabilityAnnotation, true).visitEnd()
|
||||
}
|
||||
|
||||
fun visitParameter(mv: MethodVisitor, idx: Int) {
|
||||
with(mv) {
|
||||
visitParameter(name, 0)
|
||||
if (!field.isPrimitive) {
|
||||
visitParameterAnnotation(idx, nullabilityAnnotation, true).visitEnd()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun copy(name: String, field: Class<out Any?>): Field
|
||||
abstract fun nullTest(mv: MethodVisitor, slot: Int)
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
class NonNullableField(field: Class<out Any?>) : Field(field) {
|
||||
override val nullabilityAnnotation = "Ljavax/annotation/Nonnull;"
|
||||
|
||||
constructor(name: String, field: Class<out Any?>) : this(field) {
|
||||
this.name = name
|
||||
}
|
||||
|
||||
override fun copy(name: String, field: Class<out Any?>) = NonNullableField(name, field)
|
||||
|
||||
override fun nullTest(mv: MethodVisitor, slot: Int) {
|
||||
assert(name != unsetName)
|
||||
|
||||
if (!field.isPrimitive) {
|
||||
with(mv) {
|
||||
visitVarInsn(ALOAD, 0) // load this
|
||||
visitVarInsn(ALOAD, slot) // load parameter
|
||||
visitLdcInsn("param \"$name\" cannot be null")
|
||||
visitMethodInsn(INVOKESTATIC,
|
||||
"java/util/Objects",
|
||||
"requireNonNull",
|
||||
"(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;", false)
|
||||
visitInsn(POP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
class NullableField(field: Class<out Any?>) : Field(field) {
|
||||
override val nullabilityAnnotation = "Ljavax/annotation/Nullable;"
|
||||
|
||||
constructor(name: String, field: Class<out Any?>) : this(field) {
|
||||
if (field.isPrimitive) {
|
||||
throw NullablePrimitiveException (
|
||||
"Field $name is primitive type ${Type.getDescriptor(field)} and thus cannot be nullable")
|
||||
}
|
||||
|
||||
this.name = name
|
||||
}
|
||||
|
||||
override fun copy(name: String, field: Class<out Any?>) = NullableField(name, field)
|
||||
|
||||
override fun nullTest(mv: MethodVisitor, slot: Int) {
|
||||
assert(name != unsetName)
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
||||
object FieldFactory {
|
||||
fun newInstance (mandatory: Boolean, name: String, field: Class<out Any?>) =
|
||||
if (mandatory) NonNullableField (name, field) else NullableField (name, field)
|
||||
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************/
|
||||
|
@ -8,7 +8,7 @@ import net.corda.core.serialization.CordaSerializable
|
||||
import net.corda.core.serialization.EmptyWhitelist
|
||||
import net.corda.core.serialization.KryoAMQPSerializer
|
||||
import net.corda.core.serialization.amqp.SerializerFactory.Companion.isPrimitive
|
||||
import net.corda.core.utilities.CordaRuntimeException
|
||||
import net.corda.core.CordaRuntimeException
|
||||
import net.corda.nodeapi.RPCException
|
||||
import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MEGA_CORP_PUBKEY
|
||||
|
@ -31,7 +31,7 @@ class ClassCarpenterTest {
|
||||
|
||||
@Test
|
||||
fun prims() {
|
||||
val clazz = cc.build(ClassCarpenter.ClassSchema(
|
||||
val clazz = cc.build(ClassSchema(
|
||||
"gen.Prims",
|
||||
mapOf(
|
||||
"anIntField" to Int::class.javaPrimitiveType!!,
|
||||
@ -42,7 +42,7 @@ class ClassCarpenterTest {
|
||||
"floatMyBoat" to Float::class.javaPrimitiveType!!,
|
||||
"byteMe" to Byte::class.javaPrimitiveType!!,
|
||||
"booleanField" to Boolean::class.javaPrimitiveType!!).mapValues {
|
||||
ClassCarpenter.NonNullableField (it.value)
|
||||
NonNullableField (it.value)
|
||||
}))
|
||||
assertEquals(8, clazz.nonSyntheticFields.size)
|
||||
assertEquals(10, clazz.nonSyntheticMethods.size)
|
||||
@ -72,7 +72,7 @@ class ClassCarpenterTest {
|
||||
val clazz = cc.build(ClassSchema("gen.Person", mapOf(
|
||||
"age" to Int::class.javaPrimitiveType!!,
|
||||
"name" to String::class.java
|
||||
).mapValues { ClassCarpenter.NonNullableField (it.value) } ))
|
||||
).mapValues { NonNullableField (it.value) } ))
|
||||
val i = clazz.constructors[0].newInstance(32, "Mike")
|
||||
return Pair(clazz, i)
|
||||
}
|
||||
@ -90,7 +90,7 @@ class ClassCarpenterTest {
|
||||
assertEquals("Person{age=32, name=Mike}", i.toString())
|
||||
}
|
||||
|
||||
@Test(expected = ClassCarpenter.DuplicateNameException::class)
|
||||
@Test(expected = DuplicateNameException::class)
|
||||
fun duplicates() {
|
||||
cc.build(ClassSchema("gen.EmptyClass", emptyMap(), null))
|
||||
cc.build(ClassSchema("gen.EmptyClass", emptyMap(), null))
|
||||
@ -99,8 +99,8 @@ class ClassCarpenterTest {
|
||||
@Test
|
||||
fun `can refer to each other`() {
|
||||
val (clazz1, i) = genPerson()
|
||||
val clazz2 = cc.build(ClassCarpenter.ClassSchema("gen.Referee", mapOf(
|
||||
"ref" to ClassCarpenter.NonNullableField (clazz1)
|
||||
val clazz2 = cc.build(ClassSchema("gen.Referee", mapOf(
|
||||
"ref" to NonNullableField (clazz1)
|
||||
)))
|
||||
val i2 = clazz2.constructors[0].newInstance(i)
|
||||
assertEquals(i, (i2 as SimpleFieldAccess)["ref"])
|
||||
@ -108,13 +108,13 @@ class ClassCarpenterTest {
|
||||
|
||||
@Test
|
||||
fun superclasses() {
|
||||
val schema1 = ClassCarpenter.ClassSchema(
|
||||
val schema1 = ClassSchema(
|
||||
"gen.A",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField (String::class.java)))
|
||||
mapOf("a" to NonNullableField (String::class.java)))
|
||||
|
||||
val schema2 = ClassCarpenter.ClassSchema(
|
||||
val schema2 = ClassSchema(
|
||||
"gen.B",
|
||||
mapOf("b" to ClassCarpenter.NonNullableField (String::class.java)),
|
||||
mapOf("b" to NonNullableField (String::class.java)),
|
||||
schema1)
|
||||
|
||||
val clazz = cc.build(schema2)
|
||||
@ -126,12 +126,12 @@ class ClassCarpenterTest {
|
||||
|
||||
@Test
|
||||
fun interfaces() {
|
||||
val schema1 = ClassCarpenter.ClassSchema(
|
||||
val schema1 = ClassSchema(
|
||||
"gen.A",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField(String::class.java)))
|
||||
mapOf("a" to NonNullableField(String::class.java)))
|
||||
|
||||
val schema2 = ClassCarpenter.ClassSchema("gen.B",
|
||||
mapOf("b" to ClassCarpenter.NonNullableField(Int::class.java)),
|
||||
val schema2 = ClassSchema("gen.B",
|
||||
mapOf("b" to NonNullableField(Int::class.java)),
|
||||
schema1,
|
||||
interfaces = listOf(DummyInterface::class.java))
|
||||
|
||||
@ -141,15 +141,15 @@ class ClassCarpenterTest {
|
||||
assertEquals(1, i.b)
|
||||
}
|
||||
|
||||
@Test(expected = ClassCarpenter.InterfaceMismatchException::class)
|
||||
@Test(expected = InterfaceMismatchException::class)
|
||||
fun `mismatched interface`() {
|
||||
val schema1 = ClassCarpenter.ClassSchema(
|
||||
val schema1 = ClassSchema(
|
||||
"gen.A",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField(String::class.java)))
|
||||
mapOf("a" to NonNullableField(String::class.java)))
|
||||
|
||||
val schema2 = ClassCarpenter.ClassSchema(
|
||||
val schema2 = ClassSchema(
|
||||
"gen.B",
|
||||
mapOf("c" to ClassCarpenter.NonNullableField(Int::class.java)),
|
||||
mapOf("c" to NonNullableField(Int::class.java)),
|
||||
schema1,
|
||||
interfaces = listOf(DummyInterface::class.java))
|
||||
|
||||
@ -160,9 +160,9 @@ class ClassCarpenterTest {
|
||||
|
||||
@Test
|
||||
fun `generate interface`() {
|
||||
val schema1 = ClassCarpenter.InterfaceSchema(
|
||||
val schema1 = InterfaceSchema(
|
||||
"gen.Interface",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField (Int::class.java)))
|
||||
mapOf("a" to NonNullableField (Int::class.java)))
|
||||
|
||||
val iface = cc.build(schema1)
|
||||
|
||||
@ -173,7 +173,7 @@ class ClassCarpenterTest {
|
||||
|
||||
val schema2 = ClassSchema(
|
||||
"gen.Derived",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField (Int::class.java)),
|
||||
mapOf("a" to NonNullableField (Int::class.java)),
|
||||
interfaces = listOf(iface))
|
||||
|
||||
val clazz = cc.build(schema2)
|
||||
@ -185,25 +185,25 @@ class ClassCarpenterTest {
|
||||
|
||||
@Test
|
||||
fun `generate multiple interfaces`() {
|
||||
val iFace1 = ClassCarpenter.InterfaceSchema(
|
||||
val iFace1 = InterfaceSchema(
|
||||
"gen.Interface1",
|
||||
mapOf(
|
||||
"a" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"b" to ClassCarpenter.NonNullableField(String::class.java)))
|
||||
"a" to NonNullableField(Int::class.java),
|
||||
"b" to 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)))
|
||||
"c" to NonNullableField(Int::class.java),
|
||||
"d" to NonNullableField(String::class.java)))
|
||||
|
||||
val class1 = ClassSchema(
|
||||
"gen.Derived",
|
||||
mapOf(
|
||||
"a" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"b" to ClassCarpenter.NonNullableField(String::class.java),
|
||||
"c" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"d" to ClassCarpenter.NonNullableField(String::class.java)),
|
||||
"a" to NonNullableField(Int::class.java),
|
||||
"b" to NonNullableField(String::class.java),
|
||||
"c" to NonNullableField(Int::class.java),
|
||||
"d" to NonNullableField(String::class.java)),
|
||||
interfaces = listOf(cc.build(iFace1), cc.build(iFace2)))
|
||||
|
||||
val clazz = cc.build(class1)
|
||||
@ -224,23 +224,23 @@ class ClassCarpenterTest {
|
||||
val iFace1 = InterfaceSchema(
|
||||
"gen.Interface1",
|
||||
mapOf(
|
||||
"a" to ClassCarpenter.NonNullableField (Int::class.java),
|
||||
"b" to ClassCarpenter.NonNullableField(String::class.java)))
|
||||
"a" to NonNullableField (Int::class.java),
|
||||
"b" to NonNullableField(String::class.java)))
|
||||
|
||||
val iFace2 = InterfaceSchema(
|
||||
"gen.Interface2",
|
||||
mapOf(
|
||||
"c" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"d" to ClassCarpenter.NonNullableField(String::class.java)),
|
||||
"c" to NonNullableField(Int::class.java),
|
||||
"d" to NonNullableField(String::class.java)),
|
||||
interfaces = listOf(cc.build(iFace1)))
|
||||
|
||||
val class1 = ClassSchema(
|
||||
"gen.Derived",
|
||||
mapOf(
|
||||
"a" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"b" to ClassCarpenter.NonNullableField(String::class.java),
|
||||
"c" to ClassCarpenter.NonNullableField(Int::class.java),
|
||||
"d" to ClassCarpenter.NonNullableField(String::class.java)),
|
||||
"a" to NonNullableField(Int::class.java),
|
||||
"b" to NonNullableField(String::class.java),
|
||||
"c" to NonNullableField(Int::class.java),
|
||||
"d" to NonNullableField(String::class.java)),
|
||||
interfaces = listOf(cc.build(iFace2)))
|
||||
|
||||
val clazz = cc.build(class1)
|
||||
@ -259,9 +259,9 @@ class ClassCarpenterTest {
|
||||
@Test(expected = java.lang.IllegalArgumentException::class)
|
||||
fun `null parameter small int`() {
|
||||
val className = "iEnjoySwede"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField (Int::class.java)))
|
||||
mapOf("a" to NonNullableField (Int::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -269,12 +269,12 @@ class ClassCarpenterTest {
|
||||
clazz.constructors[0].newInstance(a)
|
||||
}
|
||||
|
||||
@Test(expected = ClassCarpenter.NullablePrimitiveException::class)
|
||||
@Test(expected = NullablePrimitiveException::class)
|
||||
fun `nullable parameter small int`() {
|
||||
val className = "iEnjoySwede"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NullableField (Int::class.java)))
|
||||
mapOf("a" to NullableField (Int::class.java)))
|
||||
|
||||
cc.build(schema)
|
||||
}
|
||||
@ -282,9 +282,9 @@ class ClassCarpenterTest {
|
||||
@Test
|
||||
fun `nullable parameter integer`() {
|
||||
val className = "iEnjoyWibble"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NullableField (Integer::class.java)))
|
||||
mapOf("a" to NullableField (Integer::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
val a1 : Int? = null
|
||||
@ -297,9 +297,9 @@ class ClassCarpenterTest {
|
||||
@Test
|
||||
fun `non nullable parameter integer with non null`() {
|
||||
val className = "iEnjoyWibble"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField (Integer::class.java)))
|
||||
mapOf("a" to NonNullableField (Integer::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -310,9 +310,9 @@ class ClassCarpenterTest {
|
||||
@Test(expected = java.lang.reflect.InvocationTargetException::class)
|
||||
fun `non nullable parameter integer with null`() {
|
||||
val className = "iEnjoyWibble"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField (Integer::class.java)))
|
||||
mapOf("a" to NonNullableField (Integer::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -324,9 +324,9 @@ class ClassCarpenterTest {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun `int array`() {
|
||||
val className = "iEnjoyPotato"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField(IntArray::class.java)))
|
||||
mapOf("a" to NonNullableField(IntArray::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -343,9 +343,9 @@ class ClassCarpenterTest {
|
||||
@Test(expected = java.lang.reflect.InvocationTargetException::class)
|
||||
fun `nullable int array throws`() {
|
||||
val className = "iEnjoySwede"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField(IntArray::class.java)))
|
||||
mapOf("a" to NonNullableField(IntArray::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -357,9 +357,9 @@ class ClassCarpenterTest {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun `integer array`() {
|
||||
val className = "iEnjoyFlan"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NonNullableField(Array<Int>::class.java)))
|
||||
mapOf("a" to NonNullableField(Array<Int>::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -377,11 +377,11 @@ class ClassCarpenterTest {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun `int array with ints`() {
|
||||
val className = "iEnjoyCrumble"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className", mapOf(
|
||||
"a" to Int::class.java,
|
||||
"b" to IntArray::class.java,
|
||||
"c" to Int::class.java).mapValues { ClassCarpenter.NonNullableField(it.value) })
|
||||
"c" to Int::class.java).mapValues { NonNullableField(it.value) })
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -399,11 +399,11 @@ class ClassCarpenterTest {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun `multiple int arrays`() {
|
||||
val className = "iEnjoyJam"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className", mapOf(
|
||||
"a" to IntArray::class.java,
|
||||
"b" to Int::class.java,
|
||||
"c" to IntArray::class.java).mapValues { ClassCarpenter.NonNullableField(it.value) })
|
||||
"c" to IntArray::class.java).mapValues { NonNullableField(it.value) })
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
val i = clazz.constructors[0].newInstance(intArrayOf(1, 2), 3, intArrayOf(4, 5, 6))
|
||||
@ -422,9 +422,9 @@ class ClassCarpenterTest {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun `string array`() {
|
||||
val className = "iEnjoyToast"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NullableField(Array<String>::class.java)))
|
||||
mapOf("a" to NullableField(Array<String>::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -440,12 +440,12 @@ class ClassCarpenterTest {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun `string arrays`() {
|
||||
val className = "iEnjoyToast"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf(
|
||||
"a" to Array<String>::class.java,
|
||||
"b" to String::class.java,
|
||||
"c" to Array<String>::class.java).mapValues { ClassCarpenter.NullableField (it.value) })
|
||||
"c" to Array<String>::class.java).mapValues { NullableField (it.value) })
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
@ -469,10 +469,10 @@ class ClassCarpenterTest {
|
||||
@Test
|
||||
fun `nullable sets annotations`() {
|
||||
val className = "iEnjoyJam"
|
||||
val schema = ClassCarpenter.ClassSchema(
|
||||
val schema = ClassSchema(
|
||||
"gen.$className",
|
||||
mapOf("a" to ClassCarpenter.NullableField(String::class.java),
|
||||
"b" to ClassCarpenter.NonNullableField(String::class.java)))
|
||||
mapOf("a" to NullableField(String::class.java),
|
||||
"b" to NonNullableField(String::class.java)))
|
||||
|
||||
val clazz = cc.build(schema)
|
||||
|
||||
|
@ -145,7 +145,7 @@ class SingleMemberCompositeSchemaToClassCarpenterTests : AmqpCarpenterBase() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun singleDouble() {
|
||||
fun singleDouble() {
|
||||
val test = 10.0
|
||||
|
||||
@CordaSerializable
|
||||
|
Loading…
x
Reference in New Issue
Block a user