Add alt serialise method that returns the schema and the bytes

For future testing it would be nice, post serialisation, to have easy
access to the serialised objects schema so we can check how it was
serialised. Adding a helper function to return a data class that does
this in the same way we can for deserialize
This commit is contained in:
Katelyn Baker
2017-08-29 15:20:43 +01:00
parent a84cd567d8
commit 1e023fcf54
4 changed files with 83 additions and 23 deletions

View File

@ -8,6 +8,7 @@ import java.nio.ByteBuffer
import java.util.*
import kotlin.collections.LinkedHashSet
/**
* Main entry point for serializing an object to AMQP.
*
@ -18,37 +19,46 @@ open class SerializationOutput(internal val serializerFactory: SerializerFactory
// TODO: we're not supporting object refs yet
private val objectHistory: MutableMap<Any, Int> = IdentityHashMap()
private val serializerHistory: MutableSet<AMQPSerializer<*>> = LinkedHashSet()
private val schemaHistory: MutableSet<TypeNotation> = LinkedHashSet()
internal val schemaHistory: MutableSet<TypeNotation> = LinkedHashSet()
/**
* Serialize the given object to AMQP, wrapped in our [Envelope] wrapper which carries an AMQP 1.0 schema, and prefixed
* with a header to indicate that this is serialized with AMQP and not [Kryo], and what version of the Corda implementation
* of AMQP serialization contructed the serialized form.
* of AMQP serialization constructed the serialized form.
*/
@Throws(NotSerializableException::class)
fun <T : Any> serialize(obj: T): SerializedBytes<T> {
try {
val data = Data.Factory.create()
data.withDescribed(Envelope.DESCRIPTOR_OBJECT) {
withList {
// Our object
writeObject(obj, this)
// The schema
writeSchema(Schema(schemaHistory.toList()), this)
}
}
val bytes = ByteArray(data.encodedSize().toInt() + 8)
val buf = ByteBuffer.wrap(bytes)
buf.put(AmqpHeaderV1_0.bytes)
data.encode(buf)
return SerializedBytes(bytes)
return _serialize(obj)
} finally {
objectHistory.clear()
serializerHistory.clear()
schemaHistory.clear()
andFinally()
}
}
internal fun andFinally() {
objectHistory.clear()
serializerHistory.clear()
schemaHistory.clear()
}
internal fun <T : Any> _serialize(obj: T): SerializedBytes<T> {
val data = Data.Factory.create()
data.withDescribed(Envelope.DESCRIPTOR_OBJECT) {
withList {
// Our object
writeObject(obj, this)
// The schema
writeSchema(Schema(schemaHistory.toList()), this)
}
}
val bytes = ByteArray(data.encodedSize().toInt() + 8)
val buf = ByteBuffer.wrap(bytes)
buf.put(AmqpHeaderV1_0.bytes)
data.encode(buf)
return SerializedBytes(bytes)
}
internal fun writeObject(obj: Any, data: Data) {
writeObject(obj, data, obj.javaClass)
}

View File

@ -1,8 +1,11 @@
package net.corda.nodeapi.internal.serialization.amqp
import net.corda.core.serialization.SerializedBytes
import org.apache.qpid.proton.codec.Data
import net.corda.nodeapi.internal.serialization.AllWhitelist
import net.corda.nodeapi.internal.serialization.EmptyWhitelist
import java.io.NotSerializableException
fun testDefaultFactory() = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
fun testDefaultFactoryWithWhitelist() = SerializerFactory(EmptyWhitelist, ClassLoader.getSystemClassLoader())
@ -17,3 +20,18 @@ class TestSerializationOutput(
super.writeSchema(schema, data)
}
}
fun testName(): String = Thread.currentThread().stackTrace[2].methodName
data class BytesAndSchema<T : Any>(val obj: SerializedBytes<T>, val schema: Schema)
// Extension for the serialize routine that returns the scheme encoded into the
// bytes as well as the bytes for simple testing
@Throws(NotSerializableException::class)
fun <T : Any> SerializationOutput.serializeRtnSchema(obj: T): BytesAndSchema<T> {
try {
return BytesAndSchema(_serialize(obj), Schema(schemaHistory.toList()))
} finally {
andFinally()
}
}

View File

@ -7,11 +7,9 @@ import kotlin.test.assertNotEquals
import kotlin.test.assertTrue
class DeserializeAndReturnEnvelopeTests {
fun testName(): String = Thread.currentThread().stackTrace[2].methodName
// the 'this' reference means we can't just move this to the common test utils
@Suppress("NOTHING_TO_INLINE")
inline fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
@Test
fun oneType() {

View File

@ -0,0 +1,34 @@
package net.corda.nodeapi.internal.serialization.amqp
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
class SerializeAndReturnSchemaTest {
// the 'this' reference means we can't just move this to the common test utils
@Suppress("NOTHING_TO_INLINE")
inline private fun classTestName(clazz: String) = "${this.javaClass.name}\$${testName()}\$$clazz"
val factory = testDefaultFactory()
// just a simple test to verify the internal test extension for serialize does
// indeed give us the correct schema back. This is more useful in support of other
// tests rather than by itself but for those to be reliable this also needs
// testing
@Test
fun getSchema() {
data class C(val a: Int, val b: Int)
val a = 1
val b = 2
val sc = SerializationOutput(factory).serializeRtnSchema(C(a, b))
assertEquals(1, sc.schema.types.size)
assertEquals(classTestName("C"), sc.schema.types.first().name)
assertTrue(sc.schema.types.first() is CompositeType)
assertEquals(2, (sc.schema.types.first() as CompositeType).fields.size)
assertNotNull((sc.schema.types.first() as CompositeType).fields.find { it.name == "a" })
assertNotNull((sc.schema.types.first() as CompositeType).fields.find { it.name == "b" })
}
}