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