mirror of
https://github.com/corda/corda.git
synced 2024-12-21 22:07:55 +00:00
Some additional serializers to fill in the blanks vs. our default whitelist (#1490)
This commit is contained in:
parent
b102900c90
commit
988e3e5007
@ -64,7 +64,7 @@ abstract class SerializationFactory {
|
||||
val priorContext = _currentFactory.get()
|
||||
_currentFactory.set(this)
|
||||
try {
|
||||
return block()
|
||||
return this.block()
|
||||
} finally {
|
||||
_currentFactory.set(priorContext)
|
||||
}
|
||||
|
@ -54,6 +54,11 @@ abstract class AbstractAMQPSerializationScheme : SerializationScheme {
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.ClassSerializer(this))
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.X509CertificateHolderSerializer)
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.PartyAndCertificateSerializer(factory))
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.StringBufferSerializer)
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.SimpleStringSerializer)
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer)
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.BitSetSerializer(this))
|
||||
register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(this))
|
||||
}
|
||||
val customizer = AMQPSerializationCustomization(factory)
|
||||
pluginRegistries.forEach { it.customizeSerialization(customizer) }
|
||||
|
@ -29,6 +29,11 @@ abstract class CustomSerializer<T> : AMQPSerializer<T> {
|
||||
*/
|
||||
abstract val schemaForDocumentation: Schema
|
||||
|
||||
/**
|
||||
* Whether subclasses using this serializer via inheritance should have a mapping in the schema.
|
||||
*/
|
||||
open val revealSubclassesInSchema: Boolean = false
|
||||
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
data.withDescribed(descriptor) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
@ -86,7 +86,7 @@ class DeserializedParameterizedType(private val rawType: Class<*>, private val p
|
||||
if (pos == typeStart) {
|
||||
skippingWhitespace = false
|
||||
if (params[pos].isWhitespace()) {
|
||||
typeStart = pos++
|
||||
typeStart = ++pos
|
||||
} else if (!needAType) {
|
||||
throw NotSerializableException("Not expecting a type")
|
||||
} else if (params[pos] == '?') {
|
||||
|
@ -18,7 +18,7 @@ private typealias MapCreationFunction = (Map<*, *>) -> Map<*, *>
|
||||
*/
|
||||
class MapSerializer(private val declaredType: ParameterizedType, factory: SerializerFactory) : AMQPSerializer<Any> {
|
||||
override val type: Type = declaredType as? DeserializedParameterizedType ?: DeserializedParameterizedType.make(SerializerFactory.nameForType(declaredType))
|
||||
override val typeDescriptor = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}")
|
||||
override val typeDescriptor: Symbol = Symbol.valueOf("$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}")
|
||||
|
||||
companion object {
|
||||
// NB: Order matters in this map, the most specific classes should be listed at the end
|
||||
@ -29,7 +29,11 @@ class MapSerializer(private val declaredType: ParameterizedType, factory: Serial
|
||||
NavigableMap::class.java to { map -> Collections.unmodifiableNavigableMap(TreeMap(map)) },
|
||||
// concrete classes for user convenience
|
||||
LinkedHashMap::class.java to { map -> LinkedHashMap(map) },
|
||||
TreeMap::class.java to { map -> TreeMap(map) }
|
||||
TreeMap::class.java to { map -> TreeMap(map) },
|
||||
EnumMap::class.java to { map ->
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
EnumMap(map as Map<EnumJustUsedForCasting, Any>)
|
||||
}
|
||||
))
|
||||
|
||||
private fun findConcreteType(clazz: Class<*>): MapCreationFunction {
|
||||
@ -95,6 +99,10 @@ class MapSerializer(private val declaredType: ParameterizedType, factory: Serial
|
||||
private fun readEntry(schema: Schema, input: DeserializationInput, entry: Map.Entry<Any?, Any?>) =
|
||||
input.readObjectOrNull(entry.key, schema, declaredType.actualTypeArguments[0]) to
|
||||
input.readObjectOrNull(entry.value, schema, declaredType.actualTypeArguments[1])
|
||||
|
||||
// Cannot use * as a bound for EnumMap and EnumSet since * is not an enum. So, we use a sample enum instead.
|
||||
// We don't actually care about the type, we just need to make the compiler happier.
|
||||
internal enum class EnumJustUsedForCasting { NOT_USED }
|
||||
}
|
||||
|
||||
internal fun Class<*>.checkSupportedMapType() {
|
||||
|
@ -468,7 +468,8 @@ private fun fingerprintForType(type: Type, contextType: Type?, alreadySeen: Muta
|
||||
}
|
||||
}
|
||||
|
||||
private fun isCollectionOrMap(type: Class<*>) = Collection::class.java.isAssignableFrom(type) || Map::class.java.isAssignableFrom(type)
|
||||
private fun isCollectionOrMap(type: Class<*>) = (Collection::class.java.isAssignableFrom(type) || Map::class.java.isAssignableFrom(type)) &&
|
||||
!EnumSet::class.java.isAssignableFrom(type)
|
||||
|
||||
private fun fingerprintForObject(type: Type, contextType: Type?, alreadySeen: MutableSet<Type>, hasher: Hasher, factory: SerializerFactory): Hasher {
|
||||
// Hash the class + properties + interfaces
|
||||
|
@ -13,7 +13,7 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
import javax.annotation.concurrent.ThreadSafe
|
||||
|
||||
data class schemaAndDescriptor(val schema: Schema, val typeDescriptor: Any)
|
||||
data class FactorySchemaAndDescriptor(val schema: Schema, val typeDescriptor: Any)
|
||||
|
||||
/**
|
||||
* Factory of serializers designed to be shared across threads and invocations.
|
||||
@ -22,8 +22,8 @@ data class schemaAndDescriptor(val schema: Schema, val typeDescriptor: Any)
|
||||
// TODO: maybe support for caching of serialized form of some core types for performance
|
||||
// TODO: profile for performance in general
|
||||
// TODO: use guava caches etc so not unbounded
|
||||
// TODO: do we need to support a transient annotation to exclude certain properties?
|
||||
// TODO: allow definition of well known types that are left out of the schema.
|
||||
// TODO: migrate some core types to unsigned integer descriptor
|
||||
// TODO: document and alert to the fact that classes cannot default superclass/interface properties otherwise they are "erased" due to matching with constructor.
|
||||
// TODO: type name prefixes for interfaces and abstract classes? Or use label?
|
||||
// TODO: generic types should define restricted type alias with source of the wildcarded version, I think, if we're to generate classes from schema
|
||||
@ -64,7 +64,8 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
// Declared class may not be set to Collection, but actual class could be a collection.
|
||||
// In this case use of CollectionSerializer is perfectly appropriate.
|
||||
(Collection::class.java.isAssignableFrom(declaredClass) ||
|
||||
(actualClass != null && Collection::class.java.isAssignableFrom(actualClass))) -> {
|
||||
(actualClass != null && Collection::class.java.isAssignableFrom(actualClass))) &&
|
||||
!EnumSet::class.java.isAssignableFrom(actualClass ?: declaredClass) -> {
|
||||
val declaredTypeAmended= CollectionSerializer.deriveParameterizedType(declaredType, declaredClass, actualClass)
|
||||
serializersByType.computeIfAbsent(declaredTypeAmended) {
|
||||
CollectionSerializer(declaredTypeAmended, this)
|
||||
@ -79,7 +80,7 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
makeMapSerializer(declaredTypeAmended)
|
||||
}
|
||||
}
|
||||
Enum::class.java.isAssignableFrom(declaredClass) -> serializersByType.computeIfAbsent(declaredClass) {
|
||||
Enum::class.java.isAssignableFrom(actualClass ?: declaredClass) -> serializersByType.computeIfAbsent(actualClass ?: declaredClass) {
|
||||
EnumSerializer(actualType, actualClass ?: declaredClass, this)
|
||||
}
|
||||
else -> makeClassSerializer(actualClass ?: declaredClass, actualType, declaredType)
|
||||
@ -164,7 +165,7 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
@Throws(NotSerializableException::class)
|
||||
fun get(typeDescriptor: Any, schema: Schema): AMQPSerializer<Any> {
|
||||
return serializersByDescriptor[typeDescriptor] ?: {
|
||||
processSchema(schemaAndDescriptor(schema, typeDescriptor))
|
||||
processSchema(FactorySchemaAndDescriptor(schema, typeDescriptor))
|
||||
serializersByDescriptor[typeDescriptor] ?: throw NotSerializableException(
|
||||
"Could not find type matching descriptor $typeDescriptor.")
|
||||
}()
|
||||
@ -188,7 +189,7 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
* Iterate over an AMQP schema, for each type ascertain weather it's on ClassPath of [classloader] amd
|
||||
* if not use the [ClassCarpenter] to generate a class to use in it's place
|
||||
*/
|
||||
private fun processSchema(schema: schemaAndDescriptor, sentinel: Boolean = false) {
|
||||
private fun processSchema(schema: FactorySchemaAndDescriptor, sentinel: Boolean = false) {
|
||||
val carpenterSchemas = CarpenterSchemas.newInstance()
|
||||
for (typeNotation in schema.schema.types) {
|
||||
try {
|
||||
@ -234,8 +235,7 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
} else {
|
||||
findCustomSerializer(clazz, declaredType) ?: run {
|
||||
if (type.isArray()) {
|
||||
// Allow Object[] since this can be quite common (i.e. an untyped array)
|
||||
if (type.componentType() != Object::class.java) whitelisted(type.componentType())
|
||||
// Don't need to check the whitelist since each element will come back through the whitelisting process.
|
||||
if (clazz.componentType.isPrimitive) PrimArraySerializer.make(type, this)
|
||||
else ArraySerializer.make(type, this)
|
||||
} else if (clazz.kotlin.objectInstance != null) {
|
||||
@ -256,7 +256,7 @@ class SerializerFactory(val whitelist: ClassWhitelist, cl: ClassLoader) {
|
||||
for (customSerializer in customSerializers) {
|
||||
if (customSerializer.isSerializerFor(clazz)) {
|
||||
val declaredSuperClass = declaredType.asClass()?.superclass
|
||||
if (declaredSuperClass == null || !customSerializer.isSerializerFor(declaredSuperClass)) {
|
||||
if (declaredSuperClass == null || !customSerializer.isSerializerFor(declaredSuperClass) || !customSerializer.revealSubclassesInSchema) {
|
||||
return customSerializer
|
||||
} else {
|
||||
// Make a subclass serializer for the subclass and return that...
|
||||
|
@ -0,0 +1,17 @@
|
||||
package net.corda.nodeapi.internal.serialization.amqp.custom
|
||||
|
||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
||||
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* A serializer that writes out a [BitSet] as an integer number of bits, plus the necessary number of bytes to encode that
|
||||
* many bits.
|
||||
*/
|
||||
class BitSetSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<BitSet, BitSetSerializer.BitSetProxy>(BitSet::class.java, BitSetProxy::class.java, factory) {
|
||||
override fun toProxy(obj: BitSet): BitSetProxy = BitSetProxy(obj.toByteArray())
|
||||
|
||||
override fun fromProxy(proxy: BitSetProxy): BitSet = BitSet.valueOf(proxy.bytes)
|
||||
|
||||
data class BitSetProxy(val bytes: ByteArray)
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package net.corda.nodeapi.internal.serialization.amqp.custom
|
||||
|
||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
||||
import net.corda.nodeapi.internal.serialization.amqp.MapSerializer
|
||||
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
|
||||
import java.util.*
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
/**
|
||||
* A serializer that writes out an [EnumSet] as a type, plus list of instances in the set.
|
||||
*/
|
||||
class EnumSetSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<EnumSet<*>, EnumSetSerializer.EnumSetProxy>(EnumSet::class.java, EnumSetProxy::class.java, factory) {
|
||||
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(ClassSerializer(factory))
|
||||
|
||||
override fun toProxy(obj: EnumSet<*>): EnumSetProxy = EnumSetProxy(elementType(obj), obj.toList())
|
||||
|
||||
private fun elementType(set: EnumSet<*>): Class<*> {
|
||||
return if (set.isEmpty()) {
|
||||
EnumSet.complementOf(set as EnumSet<MapSerializer.EnumJustUsedForCasting>).first().javaClass
|
||||
} else {
|
||||
set.first().javaClass
|
||||
}
|
||||
}
|
||||
|
||||
override fun fromProxy(proxy: EnumSetProxy): EnumSet<*> {
|
||||
return if (proxy.elements.isEmpty()) {
|
||||
EnumSet.noneOf(proxy.clazz as Class<MapSerializer.EnumJustUsedForCasting>)
|
||||
} else {
|
||||
EnumSet.copyOf(proxy.elements as List<MapSerializer.EnumJustUsedForCasting>)
|
||||
}
|
||||
}
|
||||
|
||||
data class EnumSetProxy(val clazz: Class<*>, val elements: List<Any>)
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package net.corda.nodeapi.internal.serialization.amqp.custom
|
||||
|
||||
import net.corda.nodeapi.internal.serialization.amqp.*
|
||||
import org.apache.qpid.proton.amqp.Binary
|
||||
import org.apache.qpid.proton.codec.Data
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.InputStream
|
||||
import java.lang.reflect.Type
|
||||
|
||||
/**
|
||||
* A serializer that writes out the content of an input stream as bytes and deserializes into a [ByteArrayInputStream].
|
||||
*/
|
||||
object InputStreamSerializer : CustomSerializer.Implements<InputStream>(InputStream::class.java) {
|
||||
override val revealSubclassesInSchema: Boolean = true
|
||||
|
||||
override val schemaForDocumentation = Schema(listOf(RestrictedType(type.toString(), "", listOf(type.toString()), SerializerFactory.primitiveTypeName(ByteArray::class.java)!!, descriptor, emptyList())))
|
||||
|
||||
override fun writeDescribedObject(obj: InputStream, data: Data, type: Type, output: SerializationOutput) {
|
||||
val startingSize = maxOf(4096, obj.available() + 1)
|
||||
var buffer = ByteArray(startingSize)
|
||||
var pos = 0
|
||||
while (true) {
|
||||
val numberOfBytesRead = obj.read(buffer, pos, buffer.size - pos)
|
||||
if (numberOfBytesRead != -1) {
|
||||
pos += numberOfBytesRead
|
||||
// If the buffer is now full, resize it.
|
||||
if (pos == buffer.size) {
|
||||
buffer = buffer.copyOf(buffer.size + maxOf(4096, obj.available() + 1))
|
||||
}
|
||||
} else {
|
||||
data.putBinary(Binary(buffer, 0, pos))
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun readObject(obj: Any, schema: Schema, input: DeserializationInput): InputStream {
|
||||
val bits = input.readObject(obj, schema, ByteArray::class.java) as ByteArray
|
||||
return ByteArrayInputStream(bits)
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package net.corda.nodeapi.internal.serialization.amqp.custom
|
||||
|
||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
||||
import org.apache.activemq.artemis.api.core.SimpleString
|
||||
|
||||
/**
|
||||
* A serializer for [SimpleString].
|
||||
*/
|
||||
object SimpleStringSerializer : CustomSerializer.ToString<SimpleString>(SimpleString::class.java)
|
@ -0,0 +1,8 @@
|
||||
package net.corda.nodeapi.internal.serialization.amqp.custom
|
||||
|
||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
||||
|
||||
/**
|
||||
* A serializer for [StringBuffer].
|
||||
*/
|
||||
object StringBufferSerializer : CustomSerializer.ToString<StringBuffer>(StringBuffer::class.java)
|
@ -13,6 +13,8 @@ class ThrowableSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<T
|
||||
private val logger = loggerFor<ThrowableSerializer>()
|
||||
}
|
||||
|
||||
override val revealSubclassesInSchema: Boolean = true
|
||||
|
||||
override val additionalSerializers: Iterable<CustomSerializer<out Any>> = listOf(StackTraceElementSerializer(factory))
|
||||
|
||||
override fun toProxy(obj: Throwable): ThrowableProxy {
|
||||
|
@ -2,12 +2,14 @@ package net.corda.nodeapi.internal.serialization.amqp.custom
|
||||
|
||||
import net.corda.nodeapi.internal.serialization.amqp.CustomSerializer
|
||||
import net.corda.nodeapi.internal.serialization.amqp.SerializerFactory
|
||||
import java.time.*
|
||||
import java.time.ZoneId
|
||||
|
||||
/**
|
||||
* A serializer for [ZoneId] that uses a proxy object to write out the string form.
|
||||
*/
|
||||
class ZoneIdSerializer(factory: SerializerFactory) : CustomSerializer.Proxy<ZoneId, ZoneIdSerializer.ZoneIdProxy>(ZoneId::class.java, ZoneIdProxy::class.java, factory) {
|
||||
override val revealSubclassesInSchema: Boolean = true
|
||||
|
||||
override fun toProxy(obj: ZoneId): ZoneIdProxy = ZoneIdProxy(obj.id)
|
||||
|
||||
override fun fromProxy(proxy: ZoneIdProxy): ZoneId = ZoneId.of(proxy.id)
|
||||
|
@ -20,6 +20,7 @@ import net.corda.testing.BOB_IDENTITY
|
||||
import net.corda.testing.MEGA_CORP
|
||||
import net.corda.testing.MEGA_CORP_PUBKEY
|
||||
import net.corda.testing.withTestSerialization
|
||||
import org.apache.activemq.artemis.api.core.SimpleString
|
||||
import org.apache.qpid.proton.amqp.*
|
||||
import org.apache.qpid.proton.codec.DecoderImpl
|
||||
import org.apache.qpid.proton.codec.EncoderImpl
|
||||
@ -27,6 +28,7 @@ import org.junit.Assert.assertNotSame
|
||||
import org.junit.Assert.assertSame
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.IOException
|
||||
import java.io.NotSerializableException
|
||||
import java.math.BigDecimal
|
||||
@ -180,7 +182,7 @@ class SerializationOutputTests {
|
||||
assertTrue(Objects.deepEquals(desObj, desObj2) == expectDeserializedEqual)
|
||||
|
||||
// TODO: add some schema assertions to check correctly formed.
|
||||
return desObj2
|
||||
return desObj
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -355,7 +357,7 @@ class SerializationOutputTests {
|
||||
serdes(obj)
|
||||
}
|
||||
|
||||
@Test(expected = NotSerializableException::class)
|
||||
@Test
|
||||
fun `test TreeMap`() {
|
||||
val obj = TreeMap<Int, Foo>()
|
||||
obj[456] = Foo("Fred", 123)
|
||||
@ -720,8 +722,18 @@ class SerializationOutputTests {
|
||||
serdes(obj, factory, factory2)
|
||||
}
|
||||
|
||||
// TODO: ignored due to Proton-J bug https://issues.apache.org/jira/browse/PROTON-1551
|
||||
@Ignore
|
||||
@Test
|
||||
fun `test month serialize`() {
|
||||
val obj = Month.APRIL
|
||||
serdes(obj)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test day of week serialize`() {
|
||||
val obj = DayOfWeek.FRIDAY
|
||||
serdes(obj)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test certificate holder serialize`() {
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
@ -734,8 +746,6 @@ class SerializationOutputTests {
|
||||
serdes(obj, factory, factory2)
|
||||
}
|
||||
|
||||
// TODO: ignored due to Proton-J bug https://issues.apache.org/jira/browse/PROTON-1551
|
||||
@Ignore
|
||||
@Test
|
||||
fun `test party and certificate serialize`() {
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
@ -806,7 +816,6 @@ class SerializationOutputTests {
|
||||
|
||||
data class Bob(val byteArrays: List<ByteArray>)
|
||||
|
||||
@Ignore("Causes DeserializedParameterizedType.make() to fail")
|
||||
@Test
|
||||
fun `test list of byte arrays`() {
|
||||
val a = ByteArray(1)
|
||||
@ -815,7 +824,9 @@ class SerializationOutputTests {
|
||||
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
serdes(obj, factory, factory2)
|
||||
val obj2 = serdes(obj, factory, factory2, false, false)
|
||||
|
||||
assertNotSame(obj2.byteArrays[0], obj2.byteArrays[2])
|
||||
}
|
||||
|
||||
data class Vic(val a: List<String>, val b: List<String>)
|
||||
@ -874,4 +885,88 @@ class SerializationOutputTests {
|
||||
val objCopy = serdes(obj, factory, factory2, false, false)
|
||||
assertNotSame(objCopy.a, objCopy.b)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test StringBuffer serialize`() {
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.StringBufferSerializer)
|
||||
|
||||
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.StringBufferSerializer)
|
||||
|
||||
val obj = StringBuffer("Bob")
|
||||
val obj2 = serdes(obj, factory, factory2, false, false)
|
||||
assertEquals(obj.toString(), obj2.toString())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test SimpleString serialize`() {
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.SimpleStringSerializer)
|
||||
|
||||
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.SimpleStringSerializer)
|
||||
|
||||
val obj = SimpleString("Bob")
|
||||
serdes(obj, factory, factory2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test kotlin Unit serialize`() {
|
||||
val obj = Unit
|
||||
serdes(obj)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test kotlin Pair serialize`() {
|
||||
val obj = Pair("a", 3)
|
||||
serdes(obj)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test InputStream serialize`() {
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer)
|
||||
|
||||
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.InputStreamSerializer)
|
||||
val bytes = ByteArray(10) { it.toByte() }
|
||||
val obj = ByteArrayInputStream(bytes)
|
||||
val obj2 = serdes(obj, factory, factory2, expectedEqual = false, expectDeserializedEqual = false)
|
||||
val obj3 = ByteArrayInputStream(bytes) // Can't use original since the stream pointer has moved.
|
||||
assertEquals(obj3.available(), obj2.available())
|
||||
assertEquals(obj3.read(), obj2.read())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test EnumSet serialize`() {
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(factory))
|
||||
|
||||
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.EnumSetSerializer(factory2))
|
||||
|
||||
val obj = EnumSet.of(Month.APRIL, Month.AUGUST)
|
||||
serdes(obj, factory, factory2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test BitSet serialize`() {
|
||||
val factory = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory.register(net.corda.nodeapi.internal.serialization.amqp.custom.BitSetSerializer(factory))
|
||||
|
||||
val factory2 = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
|
||||
factory2.register(net.corda.nodeapi.internal.serialization.amqp.custom.BitSetSerializer(factory2))
|
||||
|
||||
val obj = BitSet.valueOf(kotlin.ByteArray(16) { it.toByte() }).get(0, 123)
|
||||
serdes(obj, factory, factory2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test EnumMap serialize`() {
|
||||
val obj = EnumMap<Month, Int>(Month::class.java)
|
||||
obj[Month.APRIL] = Month.APRIL.value
|
||||
obj[Month.AUGUST] = Month.AUGUST.value
|
||||
serdes(obj)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user