mirror of
https://github.com/corda/corda.git
synced 2025-01-18 18:56:28 +00:00
CORDA-904 - Fix evolver to work with setter instantiated classses (#2463)
- Cherry pick to backport from master * CORDA-904 - Make evolver work with classes that use setters * review comments * review comments * small fixs * don't include systemTest in compiler.xml
This commit is contained in:
parent
f8359a74fd
commit
f16e45abe9
2
.idea/compiler.xml
generated
2
.idea/compiler.xml
generated
@ -159,4 +159,4 @@
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_STRING" value="-parameters" />
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
@ -60,6 +60,7 @@ abstract class EvolutionSerializer(
|
||||
*/
|
||||
private fun getEvolverConstructor(type: Type, oldArgs: Map<String, OldParam>): KFunction<Any>? {
|
||||
val clazz: Class<*> = type.asClass()!!
|
||||
|
||||
if (!isConcrete(clazz)) return null
|
||||
|
||||
val oldArgumentSet = oldArgs.map { Pair(it.key as String?, it.value.property.resolvedType) }
|
||||
@ -123,7 +124,6 @@ abstract class EvolutionSerializer(
|
||||
*/
|
||||
fun make(old: CompositeType, new: ObjectSerializer,
|
||||
factory: SerializerFactory): AMQPSerializer<Any> {
|
||||
|
||||
// The order in which the properties were serialised is important and must be preserved
|
||||
val readersAsSerialized = LinkedHashMap<String, OldParam>()
|
||||
old.fields.forEach {
|
||||
@ -135,9 +135,9 @@ abstract class EvolutionSerializer(
|
||||
}
|
||||
}
|
||||
|
||||
val constructor = getEvolverConstructor(new.type, readersAsSerialized) ?:
|
||||
throw NotSerializableException(
|
||||
"Attempt to deserialize an interface: ${new.type}. Serialized form is invalid.")
|
||||
// cope with the situation where a generic interface was serialised as a type, in such cases
|
||||
// return the synthesised object which is, given the absence of a constructor, a no op
|
||||
val constructor = getEvolverConstructor(new.type, readersAsSerialized) ?: return new
|
||||
|
||||
val classProperties = new.type.asClass()?.propertyDescriptors() ?: emptyMap()
|
||||
|
||||
|
@ -98,7 +98,6 @@ data class PropertyDescriptor(var field: Field?, var setter: Method?, var getter
|
||||
}.toString()
|
||||
|
||||
constructor() : this(null, null, null, null)
|
||||
constructor(field: Field?) : this(field, null, null, null)
|
||||
|
||||
fun preferredGetter() : Method? = getter ?: iser
|
||||
}
|
||||
@ -128,9 +127,16 @@ fun Class<out Any?>.propertyDescriptors(): Map<String, PropertyDescriptor> {
|
||||
val classProperties = mutableMapOf<String, PropertyDescriptor>()
|
||||
|
||||
var clazz: Class<out Any?>? = this
|
||||
clazz!!.declaredFields.forEach { classProperties.put(it.name, PropertyDescriptor(it)) }
|
||||
|
||||
do {
|
||||
clazz!!.declaredFields.forEach { property ->
|
||||
classProperties.computeIfAbsent(property.name) {
|
||||
PropertyDescriptor()
|
||||
}.apply {
|
||||
this.field = property
|
||||
}
|
||||
}
|
||||
|
||||
// Note: It is possible for a class to have multiple instances of a function where the types
|
||||
// differ. For example:
|
||||
// interface I<out T> { val a: T }
|
||||
@ -142,7 +148,7 @@ fun Class<out Any?>.propertyDescriptors(): Map<String, PropertyDescriptor> {
|
||||
//
|
||||
// In addition, only getters that take zero parameters and setters that take a single
|
||||
// parameter will be considered
|
||||
clazz!!.declaredMethods?.map { func ->
|
||||
clazz.declaredMethods?.map { func ->
|
||||
if (!Modifier.isPublic(func.modifiers)) return@map
|
||||
if (func.name == "getClass") return@map
|
||||
|
||||
@ -231,15 +237,13 @@ internal fun <T : Any> propertiesForSerializationFromConstructor(
|
||||
|
||||
Pair(PublicPropertyReader(getter), returnType)
|
||||
} else {
|
||||
try {
|
||||
val field = clazz.getDeclaredField(param.value.name)
|
||||
Pair(PrivatePropertyReader(field, type), field.genericType)
|
||||
} catch (e: NoSuchFieldException) {
|
||||
val field = classProperties[name]!!.field ?:
|
||||
throw NotSerializableException("No property matching constructor parameter named '$name' " +
|
||||
"of '$clazz'. If using Java, check that you have the -parameters option specified " +
|
||||
"in the Java compiler. Alternately, provide a proxy serializer " +
|
||||
"(SerializationCustomSerializer) if recompiling isn't an option")
|
||||
}
|
||||
|
||||
Pair(PrivatePropertyReader(field, type), field.genericType)
|
||||
}
|
||||
} else {
|
||||
throw NotSerializableException(
|
||||
@ -324,6 +328,8 @@ private fun propertiesForSerializationFromAbstract(
|
||||
return mutableListOf<PropertyAccessorConstructor>().apply {
|
||||
properties.toList().withIndex().forEach {
|
||||
val getter = it.value.second.getter ?: return@forEach
|
||||
if (it.value.second.field == null) return@forEach
|
||||
|
||||
val returnType = resolveTypeVariables(getter.genericReturnType, type)
|
||||
this += PropertyAccessorConstructor(
|
||||
it.index,
|
||||
|
Loading…
Reference in New Issue
Block a user