为第 3 方扩展 Corda 序列化 class

Extend Corda serialization for a 3rd-party class

TL;博士;

我需要 Corda 序列化 JSON 来自 JDK 的对象。我想我可以为它添加一个自定义解析器,但我不知道如何做。

全文:

所以我有一堆 classes 充当 JSON api 的半类型安全包装器。一个例子:

@CordaSerializable
class ClaimReq(val json: JSONObject) {
    val proverDid: String = json.getString("prover_did")
    val credDefId: String = json.getString("cred_def_id")
}

当我尝试通过 Corda 通道发送这样一个 class 时,问题出现了。系统在序列化 org.json.JSONObject:

时出现问题

java.io.NotSerializableException: No constructor for deserialization found for class org.json.JSONObject. at net.corda.nodeapi.internal.serialization.amqp.SerializationHelperKt.constructorForDeserialization(SerializationHelper.kt:50) ~[corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForObject(Schema.kt:456) ~[corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.access$fingerprintForObject(Schema.kt:1) ~[corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType.invoke(Schema.kt:423) ~[corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType.invoke(Schema.kt) ~[corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintWithCustomSerializerOrElse(Schema.kt:345) ~[corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType(Schema.kt:417) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForObject(Schema.kt:459) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.access$fingerprintForObject(Schema.kt:1) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType.invoke(Schema.kt:423) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt$fingerprintForType.invoke(Schema.kt) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintWithCustomSerializerOrElse(Schema.kt:345) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType(Schema.kt:417) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType$default(Schema.kt:352) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SchemaKt.fingerprintForType(Schema.kt:328) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.ObjectSerializer.(ObjectSerializer.kt:34) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory$makeClassSerializer.apply(SerializerFactory.kt:271) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory$makeClassSerializer.apply(SerializerFactory.kt:40) [corda-node-api-3.1-corda.jar:?] at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1688) [?:1.8.0_171] at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.makeClassSerializer(SerializerFactory.kt:255) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializerFactory.get(SerializerFactory.kt:100) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.writeObject$node_api(SerializationOutput.kt:98) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.writeObject$node_api$default(SerializationOutput.kt:97) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.writeObject$node_api(SerializationOutput.kt:78) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize.invoke(SerializationOutput.kt:64) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize.invoke(SerializationOutput.kt:22) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationHelperKt.withList(SerializationHelper.kt:401) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize.invoke(SerializationOutput.kt:63) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput$_serialize.invoke(SerializationOutput.kt:22) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationHelperKt.withDescribed(SerializationHelper.kt:390) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput._serialize$node_api(SerializationOutput.kt:62) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.SerializationOutput.serialize(SerializationOutput.kt:36) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.amqp.AbstractAMQPSerializationScheme.serialize(AMQPSerializationScheme.kt:128) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize.invoke(SerializationScheme.kt:126) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize.invoke(SerializationScheme.kt:86) [corda-node-api-3.1-corda.jar:?] at net.corda.core.serialization.SerializationFactory.withCurrentContext(SerializationAPI.kt:66) [corda-core-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize.invoke(SerializationScheme.kt:126) [corda-node-api-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl$serialize.invoke(SerializationScheme.kt:86) [corda-node-api-3.1-corda.jar:?] at net.corda.core.serialization.SerializationFactory.asCurrent(SerializationAPI.kt:80) [corda-core-3.1-corda.jar:?] at net.corda.nodeapi.internal.serialization.SerializationFactoryImpl.serialize(SerializationScheme.kt:126) [corda-node-api-3.1-corda.jar:?] at net.corda.core.serialization.SerializationAPIKt.serialize(SerializationAPI.kt:221) [corda-core-3.1-corda.jar:?] at net.corda.core.serialization.SerializationAPIKt.serialize$default(SerializationAPI.kt:220) [corda-core-3.1-corda.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.createSessionData(FlowStateMachineImpl.kt:353) [corda-node-3.1-corda.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.send(FlowStateMachineImpl.kt:235) [corda-node-3.1-corda.jar:?] at net.corda.node.services.statemachine.FlowSessionImpl.send(FlowSessionImpl.kt:52) [corda-node-3.1-corda.jar:?] at net.corda.node.services.statemachine.FlowSessionImpl.send(FlowSessionImpl.kt:56) [corda-node-3.1-corda.jar:?] at com.luxoft.blockchainlab.corda.hyperledger.indy.flow.IssueClaimFlow$Prover.call(IssueClaimFlow.kt:85) [main/:?] at com.luxoft.blockchainlab.corda.hyperledger.indy.flow.IssueClaimFlow$Prover.call(IssueClaimFlow.kt:71) [main/:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:96) [corda-node-3.1-corda.jar:?] at net.corda.node.services.statemachine.FlowStateMachineImpl.run(FlowStateMachineImpl.kt:44) [corda-node-3.1-corda.jar:?] at co.paralleluniverse.fibers.Fiber.run1(Fiber.java:1092) [quasar-core-0.7.9-jdk8.jar:0.7.9] at co.paralleluniverse.fibers.Fiber.exec(Fiber.java:788) [quasar-core-0.7.9-jdk8.jar:0.7.9]

所以我用一个特定的构造函数和一个 getter:

解决了这个问题
@CordaSerializable
class ClaimReq(val json: JSONObject) {
    val proverDid: String = json.getString("prover_did")
    val credDefId: String = json.getString("cred_def_id")

    @ConstructorForDeserialization constructor(str: String) : this(JSONObject(str))
    val str = json.toString()
}

不幸的是,该解决方案需要在每个 class 声明中添加 2 行。有什么方法可以将它抽象出来,就像在 super-class 中一样?或者我可以使用自定义解析器扩展 Corda 序列化以支持 JSONObject?

任何由 Corda 框架序列化的具有多个构造函数的 classes 都需要使用 @ConstructorForDeserialization 注释其中一个构造函数。很明显,JSONObject.

中没有这个注解的构造函数

您需要为 JSONObject class 提供自定义序列化程序。请在此处查看定义自定义序列化程序的示例:https://docs.corda.net/head/cordapp-custom-serializers.html#example.

如果此序列化程序在 class路径上,它将在运行时由节点使用。