diff --git a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/CordaClassResolver.kt b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/CordaClassResolver.kt index c41d3fe3ef..682b2f85b3 100644 --- a/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/CordaClassResolver.kt +++ b/node-api/src/main/kotlin/net/corda/nodeapi/internal/serialization/CordaClassResolver.kt @@ -6,14 +6,15 @@ import com.esotericsoftware.kryo.io.Output import com.esotericsoftware.kryo.serializers.FieldSerializer import com.esotericsoftware.kryo.util.DefaultClassResolver import com.esotericsoftware.kryo.util.Util -import net.corda.nodeapi.internal.AttachmentsClassLoader import net.corda.core.serialization.ClassWhitelist import net.corda.core.serialization.CordaSerializable import net.corda.core.serialization.SerializationContext import net.corda.core.utilities.contextLogger +import net.corda.nodeapi.internal.AttachmentsClassLoader import net.corda.nodeapi.internal.serialization.amqp.hasAnnotationInHierarchy import net.corda.nodeapi.internal.serialization.kryo.ThrowableSerializer import java.io.PrintWriter +import java.lang.reflect.Modifier import java.lang.reflect.Modifier.isAbstract import java.nio.charset.StandardCharsets import java.nio.file.Files @@ -74,10 +75,21 @@ class CordaClassResolver(serializationContext: SerializationContext) : DefaultCl override fun registerImplicit(type: Class<*>): Registration { val targetType = typeForSerializationOf(type) + // Is this a Kotlin object? We use our own reflection here rather than .kotlin.objectInstance because Kotlin + // reflection won't work for private objects, and can throw exceptions in other circumstances as well. val objectInstance = try { - targetType.kotlin.objectInstance + targetType.declaredFields.singleOrNull { + it.name == "INSTANCE" && + it.type == type && + Modifier.isStatic(it.modifiers) && + Modifier.isFinal(it.modifiers) && + Modifier.isPublic(it.modifiers) + }?.let { + it.isAccessible = true + type.cast(it.get(null)!!) + } } catch (t: Throwable) { - null // objectInstance will throw if the type is something like a lambda + null } // We have to set reference to true, since the flag influences how String fields are treated and we want it to be consistent.