Don't blindly add SimpleFieldAccess as interface to carpented classes

This fix really only applies to the testing case where, to test the
carpenter as it integrates with the deserialzer we need classes not
found on the class path. To do this they can be created by a second
class carpenter

However, the original carpenter *always* added SimpleFieldAccess as an
interface to the class it would be creating. Under normal circumstances
that's fine as that interface wouldn't be in the list of interfaces
given to the carpenter for the class it's being asked to created.
However, if as described above the carpenter schema was synthesised from
a class that was carpented it will.

If this happens we get an error as understandably you can't have a
duplicate interface.

Fix is to simply check weather the list of interfaces the schema
describes and only add SimpleFieldAccess if it isn't on it
This commit is contained in:
Katelyn Baker 2017-07-27 12:13:47 +01:00
parent c721316d67
commit 337ccd47b5

View File

@ -129,10 +129,12 @@ class ClassCarpenter {
private fun generateClass(classSchema: Schema): Class<*> { private fun generateClass(classSchema: Schema): Class<*> {
return generate(classSchema) { cw, schema -> return generate(classSchema) { cw, schema ->
val superName = schema.superclass?.jvmName ?: "java/lang/Object" val superName = schema.superclass?.jvmName ?: "java/lang/Object"
val interfaces = arrayOf(SimpleFieldAccess::class.java.name.jvm) + schema.interfaces.map { it.name.jvm } var interfaces = schema.interfaces.map { it.name.jvm }.toMutableList()
if (SimpleFieldAccess::class.java !in schema.interfaces) interfaces.add(SimpleFieldAccess::class.java.name.jvm)
with(cw) { with(cw) {
visit(V1_8, ACC_PUBLIC + ACC_SUPER, schema.jvmName, null, superName, interfaces) visit(V1_8, ACC_PUBLIC + ACC_SUPER, schema.jvmName, null, superName, interfaces.toTypedArray())
generateFields(schema) generateFields(schema)
generateConstructor(schema) generateConstructor(schema)
@ -304,6 +306,11 @@ class ClassCarpenter {
+ "with 'get': ${itf.name}.${it.name}") + "with 'get': ${itf.name}.${it.name}")
} }
// if we're trying to carpent a class that prior to serialisation / deserialisation
// was made by a carpenter then we can ignore this (it will implement a plain get
// method from SimpleFieldAccess)
if (fieldNameFromItf.isEmpty() && SimpleFieldAccess::class.java in schema.interfaces) return@forEach
if ((schema is ClassSchema) and (fieldNameFromItf !in allFields)) if ((schema is ClassSchema) and (fieldNameFromItf !in allFields))
throw InterfaceMismatchException( throw InterfaceMismatchException(
"Interface ${itf.name} requires a field named $fieldNameFromItf but that " "Interface ${itf.name} requires a field named $fieldNameFromItf but that "