diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/MapSerializer.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/MapSerializer.kt index c399243445..2853ba47ee 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/MapSerializer.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/amqp/MapSerializer.kt @@ -5,6 +5,7 @@ import java.io.NotSerializableException import java.lang.reflect.ParameterizedType import java.lang.reflect.Type import java.util.* +import kotlin.collections.LinkedHashMap import kotlin.collections.Map import kotlin.collections.iterator import kotlin.collections.map @@ -17,10 +18,16 @@ class MapSerializer(val declaredType: ParameterizedType, factory: SerializerFact override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}" companion object { - private val supportedTypes: Map>, (Map<*, *>) -> Map<*, *>> = mapOf( - Map::class.java to { map -> Collections.unmodifiableMap(map) }, - SortedMap::class.java to { map -> Collections.unmodifiableSortedMap(TreeMap(map)) }, - NavigableMap::class.java to { map -> Collections.unmodifiableNavigableMap(TreeMap(map)) } + private val supportedTypes: Map, (Map<*, *>) -> Map<*, *>> = mapOf( + Map::class.java to { map -> map }, + SortedMap::class.java to { map -> TreeMap(map) }, + NavigableMap::class.java to { map -> TreeMap(map) }, + Dictionary::class.java to { map -> Hashtable(map) }, + // concrete types for user convienience + HashMap::class.java to { map -> LinkedHashMap(map) }, + LinkedHashMap::class.java to { map -> LinkedHashMap(map) }, + TreeMap::class.java to { map -> TreeMap(map) }, + Hashtable::class.java to { map -> Hashtable(map) } ) private fun findConcreteType(clazz: Class<*>): (Map<*, *>) -> Map<*, *> { diff --git a/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeMapTests.kt b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeMapTests.kt new file mode 100644 index 0000000000..da16929ccb --- /dev/null +++ b/node-api/src/test/kotlin/net/corda/nodeapi/internal/serialization/amqp/DeserializeMapTests.kt @@ -0,0 +1,93 @@ +package net.corda.nodeapi.internal.serialization.amqp + +import org.junit.Test +import java.util.* +import org.apache.qpid.proton.codec.Data + +class DeserializeCollectionTests { +class TestSerializationOutput( + private val verbose: Boolean, + serializerFactory: SerializerFactory = SerializerFactory()) : SerializationOutput(serializerFactory) { + + override fun writeSchema(schema: Schema, data: Data) { + if (verbose) println(schema) + super.writeSchema(schema, data) + } + } + companion object { + /** + * If you want to see the schema encoded into the envelope after serialisation change this to true + */ + private const val VERBOSE = false + } + + val sf = SerializerFactory() + + @Test + fun mapTest() { + data class C(val c: Map) + val c = C (mapOf("A" to 1, "B" to 2)) + + val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) + DeserializationInput(sf).deserialize(serialisedBytes) + } + + @Test + fun sortedMapTest() { + data class C(val c: SortedMap) + val c = C(sortedMapOf ("A" to 1, "B" to 2)) + val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) + DeserializationInput(sf).deserialize(serialisedBytes) + } + + @Test + fun dictionaryTest() { + data class C(val c: Dictionary) + var v : Hashtable = Hashtable() + v.put ("a", 1) + v.put ("b", 2) + val c = C(v) + val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) + DeserializationInput(sf).deserialize(serialisedBytes) + } + + @Test + fun navigableMapTest() { + data class C(val c: NavigableMap) + val c = C(TreeMap (mapOf("A" to 1, "B" to 3)).descendingMap()) + + val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) + DeserializationInput(sf).deserialize(serialisedBytes) + } + + @Test(expected=java.lang.IllegalArgumentException::class) + fun HashMapTest() { + data class C(val c : HashMap) + val c = C (HashMap (mapOf("A" to 1, "B" to 2))) + + // expect this to throw + TestSerializationOutput(VERBOSE, sf).serialize(c) + } + + @Test + fun concreteTreeMapTest() { + data class C(val c: TreeMap) + val c = C(TreeMap (mapOf("A" to 1, "B" to 3))) + + val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) + DeserializationInput(sf).deserialize(serialisedBytes) + } + + @Test + fun concreteLinkedHashMapTest() { + data class C(val c : LinkedHashMap) + val c = C (LinkedHashMap (mapOf("A" to 1, "B" to 2))) + + val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) + val deserializedObj = DeserializationInput(sf).deserialize(serialisedBytes) + } + + + + +}