Finalise which map containers to serialize

This commit is contained in:
Katelyn Baker 2017-08-10 11:59:10 +01:00
parent de05a11511
commit d2933ca8a3
4 changed files with 52 additions and 22 deletions

View File

@ -18,18 +18,23 @@ class MapSerializer(val declaredType: ParameterizedType, factory: SerializerFact
override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}" override val typeDescriptor = "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}"
companion object { companion object {
private val supportedTypes: Map<Class<out Any>, (Map<*, *>) -> Map<*, *>> = mapOf( private val supportedTypes: Map<Class<out Any?>, (Map<*, *>) -> Map<*, *>> = mapOf(
// Interfaces
Map::class.java to { map -> map }, Map::class.java to { map -> map },
SortedMap::class.java to { map -> TreeMap(map) }, SortedMap::class.java to { map -> TreeMap(map) },
NavigableMap::class.java to { map -> TreeMap(map) }, NavigableMap::class.java to { map -> TreeMap(map) },
// Sub types
Dictionary::class.java to { map -> Hashtable(map) }, Dictionary::class.java to { map -> Hashtable(map) },
// concrete types for user convienience AbstractMap::class.java to { map -> LinkedHashMap(map) },
HashMap::class.java to { map -> LinkedHashMap(map) }, // concrete types
LinkedHashMap::class.java to { map -> LinkedHashMap(map) }, LinkedHashMap::class.java to { map -> LinkedHashMap(map) },
TreeMap::class.java to { map -> TreeMap(map) }, TreeMap::class.java to { map -> TreeMap(map) },
Hashtable::class.java to { map -> Hashtable(map) } Hashtable::class.java to { map -> Hashtable(map) },
WeakHashMap::class.java to { map -> WeakHashMap(map) }
// Explicitly disallowed
// - HashMap::class.java
// - EnumMap::class.java
) )
private fun findConcreteType(clazz: Class<*>): (Map<*, *>) -> Map<*, *> { private fun findConcreteType(clazz: Class<*>): (Map<*, *>) -> Map<*, *> {
return supportedTypes[clazz] ?: throw NotSerializableException("Unsupported map type $clazz.") return supportedTypes[clazz] ?: throw NotSerializableException("Unsupported map type $clazz.")
} }

View File

@ -35,6 +35,7 @@ internal fun constructorForDeserialization(type: Type): KFunction<Any>? {
val kotlinConstructors = clazz.kotlin.constructors val kotlinConstructors = clazz.kotlin.constructors
val hasDefault = kotlinConstructors.any { it.parameters.isEmpty() } val hasDefault = kotlinConstructors.any { it.parameters.isEmpty() }
for (kotlinConstructor in kotlinConstructors) { for (kotlinConstructor in kotlinConstructors) {
println (kotlinConstructor)
if (preferredCandidate == null && kotlinConstructors.size == 1 && !hasDefault) { if (preferredCandidate == null && kotlinConstructors.size == 1 && !hasDefault) {
preferredCandidate = kotlinConstructor preferredCandidate = kotlinConstructor
} else if (preferredCandidate == null && kotlinConstructors.size == 2 && hasDefault && kotlinConstructor.parameters.isNotEmpty()) { } else if (preferredCandidate == null && kotlinConstructors.size == 2 && hasDefault && kotlinConstructor.parameters.isNotEmpty()) {
@ -44,6 +45,7 @@ internal fun constructorForDeserialization(type: Type): KFunction<Any>? {
throw NotSerializableException("More than one constructor for $clazz is annotated with @CordaConstructor.") throw NotSerializableException("More than one constructor for $clazz is annotated with @CordaConstructor.")
} }
preferredCandidate = kotlinConstructor preferredCandidate = kotlinConstructor
println (" -> $preferredCandidate")
} }
} }
return preferredCandidate ?: throw NotSerializableException("No constructor for deserialization found for $clazz.") return preferredCandidate ?: throw NotSerializableException("No constructor for deserialization found for $clazz.")

View File

@ -5,7 +5,8 @@ import java.util.*
import org.apache.qpid.proton.codec.Data import org.apache.qpid.proton.codec.Data
class DeserializeCollectionTests { class DeserializeCollectionTests {
class TestSerializationOutput(
class TestSerializationOutput(
private val verbose: Boolean, private val verbose: Boolean,
serializerFactory: SerializerFactory = SerializerFactory()) : SerializationOutput(serializerFactory) { serializerFactory: SerializerFactory = SerializerFactory()) : SerializationOutput(serializerFactory) {
@ -32,6 +33,23 @@ class TestSerializationOutput(
DeserializationInput(sf).deserialize(serialisedBytes) DeserializationInput(sf).deserialize(serialisedBytes)
} }
@Test
fun abstractMapFromMapOf() {
data class C(val c: AbstractMap<String, Int>)
val c = C (mapOf("A" to 1, "B" to 2) as AbstractMap)
val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c)
DeserializationInput(sf).deserialize(serialisedBytes)
}
@Test
fun abstractMapFromTreeMap() {
data class C(val c: AbstractMap<String, Int>)
val c = C (TreeMap(mapOf("A" to 1, "B" to 2)))
val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c)
DeserializationInput(sf).deserialize(serialisedBytes)
}
@Test @Test
fun sortedMapTest() { fun sortedMapTest() {
data class C(val c: SortedMap<String, Int>) data class C(val c: SortedMap<String, Int>)
@ -40,6 +58,15 @@ class TestSerializationOutput(
DeserializationInput(sf).deserialize(serialisedBytes) DeserializationInput(sf).deserialize(serialisedBytes)
} }
@Test
fun navigableMapTest() {
data class C(val c: NavigableMap<String, Int>)
val c = C(TreeMap (mapOf("A" to 1, "B" to 2)).descendingMap())
val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c)
DeserializationInput(sf).deserialize(serialisedBytes)
}
@Test @Test
fun dictionaryTest() { fun dictionaryTest() {
data class C(val c: Dictionary<String, Int>) data class C(val c: Dictionary<String, Int>)
@ -51,17 +78,8 @@ class TestSerializationOutput(
DeserializationInput(sf).deserialize(serialisedBytes) DeserializationInput(sf).deserialize(serialisedBytes)
} }
@Test
fun navigableMapTest() {
data class C(val c: NavigableMap<String, Int>)
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) @Test(expected=java.lang.IllegalArgumentException::class)
fun HashMapTest() { fun hashMapTest() {
data class C(val c : HashMap<String, Int>) data class C(val c : HashMap<String, Int>)
val c = C (HashMap (mapOf("A" to 1, "B" to 2))) val c = C (HashMap (mapOf("A" to 1, "B" to 2)))
@ -69,6 +87,15 @@ class TestSerializationOutput(
TestSerializationOutput(VERBOSE, sf).serialize(c) TestSerializationOutput(VERBOSE, sf).serialize(c)
} }
@Test
fun weakHashMapTest() {
data class C(val c : WeakHashMap<String, Int>)
val c = C (WeakHashMap (mapOf("A" to 1, "B" to 2)))
val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c)
DeserializationInput(sf).deserialize(serialisedBytes)
}
@Test @Test
fun concreteTreeMapTest() { fun concreteTreeMapTest() {
data class C(val c: TreeMap<String, Int>) data class C(val c: TreeMap<String, Int>)
@ -84,10 +111,6 @@ class TestSerializationOutput(
val c = C (LinkedHashMap (mapOf("A" to 1, "B" to 2))) val c = C (LinkedHashMap (mapOf("A" to 1, "B" to 2)))
val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c) val serialisedBytes = TestSerializationOutput(VERBOSE, sf).serialize(c)
val deserializedObj = DeserializationInput(sf).deserialize(serialisedBytes) DeserializationInput(sf).deserialize(serialisedBytes)
} }
} }

View File

@ -356,7 +356,7 @@ class SerializationOutputTests {
serdes(obj) serdes(obj)
} }
@Test(expected = NotSerializableException::class) @Test
fun `test TreeMap property`() { fun `test TreeMap property`() {
val obj = TreeMapWrapper(TreeMap<Int, Foo>()) val obj = TreeMapWrapper(TreeMap<Int, Foo>())
obj.tree[456] = Foo("Fred", 123) obj.tree[456] = Foo("Fred", 123)