CORDA-2687 - Ensure collections of unknown types are not carpented (#4826)

* Prevent carpenting a collection of an unknown type

* Add a comment explaining the condition used to detect collections

* Add a unit test and clarify comment around what is being carpented
This commit is contained in:
JamesHR3 2019-03-01 10:57:37 +00:00 committed by Katelyn Baker
parent d018863261
commit 6b1429d30d
3 changed files with 48 additions and 3 deletions

View File

@ -248,9 +248,13 @@ open class SerializerFactory(
logger.debug { "descriptor=${schemaAndDescriptor.typeDescriptor}, typeNotation=$name" }
name to processSchemaEntry(notation)
} catch (e: ClassNotFoundException) {
// class missing from the classpath, so load its interfaces and add it for carpenting (see method docs).
interfacesPerClass[name]!!.forEach { processSchemaEntry(it) }
metaSchema.buildFor(notation, classloader)
// Class missing from the classpath, so load its interfaces and add it for carpenting (see method docs).
// This carpenting should only be carried out for non-collections. These are detected by looking for
// types that are not composites (RestrictedTypes), and not enums (have no choices).
if (!(notation is RestrictedType && notation.choices.isEmpty())) {
interfacesPerClass[name]!!.forEach { processSchemaEntry(it) }
metaSchema.buildFor(notation, classloader)
}
null
}
}.toMap()

View File

@ -90,6 +90,47 @@ class StaticInitialisationOfSerializedObjectTest {
.doesNotContain(interfaceType.name)
}
// enum class MyEnum {
// Foo,
// Bar,
// Baz
// }
// This test checks that if a known class name is received with an additional property of type
// Collection<UnknownType>, UnknownType is carpented correctly and a usable known type is produced.
//
// To regenerate the serialized data for this test:
// - Uncomment the enum above
// - Uncomment the definition of DummyClass with the additional set and comment out the current definition
// - Uncomment the generation code and comment out all code underneath it in the test
// - Run the test. This will print a path to a new file; copy this to the test resources directory
@Test
fun collectionsOfUnknownTypesAreHandledCorrectly() {
// data class DummyClass(val a: String, val b: List<MyEnum>)
data class DummyClass(val a: String)
val path = EvolvabilityTests::class.java.getResource("StaticInitialisationOfSerializedObjectTest.unknownCollection")
val f = File(path.toURI())
// val sf = SerializerFactory(AllWhitelist, ClassLoader.getSystemClassLoader())
// val sc = SerializationOutput(sf).serialize(DummyClass("foo", listOf(MyEnum.Foo)))
// f.writeBytes(sc.bytes)
// println(path)
class WL : ClassWhitelist {
override fun hasListed(type: Class<*>): Boolean =
type.name == "net.corda.nodeapi.internal.serialization.amqp" +
".StaticInitialisationOfSerializedObjectTest\$collectionsOfUnknownTypesAreHandledCorrectly\$DummyClass"
|| type.name == "net.corda.nodeapi.internal.serialization.amqp" +
".StaticInitialisationOfSerializedObjectTest\$MyEnum"
}
val sf2 = SerializerFactory(WL(), ClassLoader.getSystemClassLoader())
val bytes = f.readBytes()
val output = DeserializationInput(sf2).deserialize(SerializedBytes<DummyClass>(bytes))
assertEquals(output.a, "foo")
}
@Test
fun deserializeTest() {