mirror of
https://github.com/corda/corda.git
synced 2025-01-18 02:39:51 +00:00
Ensure typename is calculated correctly for nested arrays
We were relying on the Java typename conversion to work for our AMQP envelope type selection, and only special casing arrays of primitives. However with nested arrays this breaks as the intermediate serialises for the nested arrays still have no idea as to what the underlaying type is as the assumption will be being made that the type is a boxed primitive. Solution is to compute the typename properly, walking down the nested array chain
This commit is contained in:
parent
6dc48e7cea
commit
b8ae03410d
@ -15,9 +15,20 @@ open class ArraySerializer(override val type: Type, factory: SerializerFactory)
|
||||
}
|
||||
}
|
||||
|
||||
// because this might be an array of array of primitives (to any recursive depth) and
|
||||
// because we care that the lowest type is unboxed we can't rely on the inbuilt type
|
||||
// id to generate it properly (it will always return [[[Ljava.lang.type -> type[][][]
|
||||
// for example).
|
||||
//
|
||||
// We *need* to retain knowledge for AMQP deserialisation weather that lowest primitive
|
||||
// was boxed or unboxed so just infer it recursively
|
||||
private fun calcTypeName(type: Type) : String =
|
||||
if (type.componentType().isArray()) "${calcTypeName(type.componentType())}[]"
|
||||
else "${type.componentType().typeName}${if (type.asClass()!!.componentType.isPrimitive) "[p]" else "[]"}"
|
||||
|
||||
override val typeDescriptor by lazy { "$DESCRIPTOR_DOMAIN:${fingerprintForType(type, factory)}" }
|
||||
internal val elementType: Type by lazy { type.componentType() }
|
||||
internal open val typeName by lazy { type.typeName }
|
||||
internal open val typeName by lazy { calcTypeName(type) }
|
||||
|
||||
internal val typeNotation: TypeNotation by lazy {
|
||||
RestrictedType(typeName, null, emptyList(), "list", Descriptor(typeDescriptor, null), emptyList())
|
||||
@ -73,13 +84,13 @@ abstract class PrimArraySerializer(type: Type, factory: SerializerFactory) : Arr
|
||||
// We don't need to handle the unboxed byte type as that is coercible to a byte array, but
|
||||
// the other 7 primitive types we do
|
||||
val primTypes: Map<Type, (SerializerFactory) -> PrimArraySerializer> = mapOf(
|
||||
IntArray::class.java to { f -> PrimIntArraySerializer(f, "int[p]") },
|
||||
CharArray::class.java to { f -> PrimCharArraySerializer(f, "char[p]") },
|
||||
BooleanArray::class.java to { f -> PrimBooleanArraySerializer(f, "boolean[p]") },
|
||||
FloatArray::class.java to { f -> PrimFloatArraySerializer(f, "float[p]") },
|
||||
ShortArray::class.java to { f -> PrimShortArraySerializer(f, "short[p]") },
|
||||
DoubleArray::class.java to { f -> PrimDoubleArraySerializer(f, "double[p]") },
|
||||
LongArray::class.java to { f -> PrimLongArraySerializer(f, "long[p]") }
|
||||
IntArray::class.java to { f -> PrimIntArraySerializer(f) },
|
||||
CharArray::class.java to { f -> PrimCharArraySerializer(f) },
|
||||
BooleanArray::class.java to { f -> PrimBooleanArraySerializer(f) },
|
||||
FloatArray::class.java to { f -> PrimFloatArraySerializer(f) },
|
||||
ShortArray::class.java to { f -> PrimShortArraySerializer(f) },
|
||||
DoubleArray::class.java to { f -> PrimDoubleArraySerializer(f) },
|
||||
LongArray::class.java to { f -> PrimLongArraySerializer(f) }
|
||||
// ByteArray::class.java <-> NOT NEEDED HERE (see comment above)
|
||||
)
|
||||
|
||||
@ -91,14 +102,14 @@ abstract class PrimArraySerializer(type: Type, factory: SerializerFactory) : Arr
|
||||
}
|
||||
}
|
||||
|
||||
class PrimIntArraySerializer(factory: SerializerFactory, override val typeName: String) :
|
||||
class PrimIntArraySerializer(factory: SerializerFactory) :
|
||||
PrimArraySerializer(IntArray::class.java, factory) {
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
localWriteObject(data) { (obj as IntArray).forEach { output.writeObjectOrNull(it, data, elementType) } }
|
||||
}
|
||||
}
|
||||
|
||||
class PrimCharArraySerializer(factory: SerializerFactory, override val typeName: String) :
|
||||
class PrimCharArraySerializer(factory: SerializerFactory) :
|
||||
PrimArraySerializer(CharArray::class.java, factory) {
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
localWriteObject(data) { (obj as CharArray).forEach { output.writeObjectOrNull(it, data, elementType) } }
|
||||
@ -114,35 +125,35 @@ class PrimCharArraySerializer(factory: SerializerFactory, override val typeName:
|
||||
}
|
||||
}
|
||||
|
||||
class PrimBooleanArraySerializer(factory: SerializerFactory, override val typeName: String) :
|
||||
class PrimBooleanArraySerializer(factory: SerializerFactory) :
|
||||
PrimArraySerializer(BooleanArray::class.java, factory) {
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
localWriteObject(data) { (obj as BooleanArray).forEach { output.writeObjectOrNull(it, data, elementType) } }
|
||||
}
|
||||
}
|
||||
|
||||
class PrimDoubleArraySerializer(factory: SerializerFactory, override val typeName: String) :
|
||||
class PrimDoubleArraySerializer(factory: SerializerFactory) :
|
||||
PrimArraySerializer(DoubleArray::class.java, factory) {
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
localWriteObject(data) { (obj as DoubleArray).forEach { output.writeObjectOrNull(it, data, elementType) } }
|
||||
}
|
||||
}
|
||||
|
||||
class PrimFloatArraySerializer(factory: SerializerFactory, override val typeName: String) :
|
||||
class PrimFloatArraySerializer(factory: SerializerFactory) :
|
||||
PrimArraySerializer(FloatArray::class.java, factory) {
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
localWriteObject(data) { (obj as FloatArray).forEach { output.writeObjectOrNull(it, data, elementType) } }
|
||||
}
|
||||
}
|
||||
|
||||
class PrimShortArraySerializer(factory: SerializerFactory, override val typeName: String) :
|
||||
class PrimShortArraySerializer(factory: SerializerFactory) :
|
||||
PrimArraySerializer(ShortArray::class.java, factory) {
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
localWriteObject(data) { (obj as ShortArray).forEach { output.writeObjectOrNull(it, data, elementType) } }
|
||||
}
|
||||
}
|
||||
|
||||
class PrimLongArraySerializer(factory: SerializerFactory, override val typeName: String) :
|
||||
class PrimLongArraySerializer(factory: SerializerFactory) :
|
||||
PrimArraySerializer(LongArray::class.java, factory) {
|
||||
override fun writeObject(obj: Any, data: Data, type: Type, output: SerializationOutput) {
|
||||
localWriteObject(data) { (obj as LongArray).forEach { output.writeObjectOrNull(it, data, elementType) } }
|
||||
|
@ -370,5 +370,63 @@ class DeserializeSimpleTypesTests {
|
||||
assertEquals(c.c[1], deserializedC.c[1])
|
||||
assertEquals(c.c[2], deserializedC.c[2])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun arrayOfArrayOfInt() {
|
||||
class C(val c: Array<Array<Int>>)
|
||||
val c = C (arrayOf (arrayOf(1,2,3), arrayOf(4,5,6)))
|
||||
|
||||
val serialisedC = TestSerializationOutput(VERBOSE, sf).serialize(c)
|
||||
val deserializedC = DeserializationInput(sf).deserialize(serialisedC)
|
||||
|
||||
assertEquals(c.c.size, deserializedC.c.size)
|
||||
assertEquals(c.c[0].size, deserializedC.c[0].size)
|
||||
assertEquals(c.c[0][0], deserializedC.c[0][0])
|
||||
assertEquals(c.c[0][1], deserializedC.c[0][1])
|
||||
assertEquals(c.c[0][2], deserializedC.c[0][2])
|
||||
assertEquals(c.c[1].size, deserializedC.c[1].size)
|
||||
assertEquals(c.c[1][0], deserializedC.c[1][0])
|
||||
assertEquals(c.c[1][1], deserializedC.c[1][1])
|
||||
assertEquals(c.c[1][2], deserializedC.c[1][2])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun arrayOfIntArray() {
|
||||
class C(val c: Array<IntArray>)
|
||||
val c = C (arrayOf (IntArray(3), IntArray(3)))
|
||||
c.c[0][0] = 1; c.c[0][1] = 2; c.c[0][2] = 3
|
||||
c.c[1][0] = 4; c.c[1][1] = 5; c.c[1][2] = 6
|
||||
|
||||
val serialisedC = TestSerializationOutput(VERBOSE, sf).serialize(c)
|
||||
val deserializedC = DeserializationInput(sf).deserialize(serialisedC)
|
||||
|
||||
assertEquals(c.c.size, deserializedC.c.size)
|
||||
assertEquals(c.c[0].size, deserializedC.c[0].size)
|
||||
assertEquals(c.c[0][0], deserializedC.c[0][0])
|
||||
assertEquals(c.c[0][1], deserializedC.c[0][1])
|
||||
assertEquals(c.c[0][2], deserializedC.c[0][2])
|
||||
assertEquals(c.c[1].size, deserializedC.c[1].size)
|
||||
assertEquals(c.c[1][0], deserializedC.c[1][0])
|
||||
assertEquals(c.c[1][1], deserializedC.c[1][1])
|
||||
assertEquals(c.c[1][2], deserializedC.c[1][2])
|
||||
}
|
||||
|
||||
@Test
|
||||
fun arrayOfArrayOfIntArray() {
|
||||
class C(val c: Array<Array<IntArray>>)
|
||||
|
||||
val c = C(arrayOf(arrayOf(IntArray(3), IntArray(3), IntArray(3)),
|
||||
arrayOf(IntArray(3), IntArray(3), IntArray(3)),
|
||||
arrayOf(IntArray(3), IntArray(3), IntArray(3))))
|
||||
|
||||
for (i in 0..2) { for (j in 0..2) { for (k in 0..2) { c.c[i][j][k] = i + j + k } } }
|
||||
|
||||
val serialisedC = TestSerializationOutput(VERBOSE, sf).serialize(c)
|
||||
val deserializedC = DeserializationInput(sf).deserialize(serialisedC)
|
||||
|
||||
for (i in 0..2) { for (j in 0..2) { for (k in 0..2) {
|
||||
assertEquals(c.c[i][j][k], deserializedC.c[i][j][k])
|
||||
}}}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user