Merge pull request #1349 from corda/feature/kat/serialiseWithEnvelopeReturn

Add alt serialise method that returns the schema and the bytes
This commit is contained in:
Katelyn Baker 2017-08-29 16:57:41 +01:00 committed by GitHub
commit 76ffd485ac
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.serializeAndReturnSchema(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).serializeAndReturnSchema(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" })
}
}