java.io.NotSerializableException: 构造函数参数 arg0 未引用 class 的 属性

java.io.NotSerializableException: Constructor parameter arg0 doesn't refer to a property of class

当 运行 Corda 合约在 IntelliJ 中测试时,在 Java 中编写的测试有时会失败并出现以下异常:

[ERROR] 17:02:51,821 [main] (Schema.kt:437) amqp.Schema.fingerprintForType - Constructor parameter arg0 doesn't refer to a property of class 'class mypackage.MyState' -> class mypackage.MyState {} java.io.NotSerializableException: Constructor parameter arg0 doesn't refer to a property of class 'class mypackage.MyState' at net.corda.nodeapi.internal.serialization.amqp.SerializationHelperKt.propertiesForSerializationFromConstructor(SerializationHelper.kt:249) ~[corda-node-api-corda-3.0.jar:?]

我该如何解决这个问题?

默认情况下,编译后的 Java 类 将为其构造函数参数使用默认名称(arg0arg1 等)。但是,出于序列化的目的,我们需要实际的参数名称。您需要Java 使用实际参数名称进行编译。

在 IntelliJ 中:

如果通过 IntelliJ 运行 nodes/tests,您可以通过将以下块添加到 .idea/compiler.xml 文件来实现:

<component name="JavacSettings">
    <option name="ADDITIONAL_OPTIONS_STRING" value="-parameters" />
</component>

或者转到 IntelliJ IDEA > Preferences > Build, Execution, Deployment > Compiler > Java Compiler 并将 -parameters 添加到 Additional command line parameters:框。

要让 IntelliJ 接受编译器设置中的更改,请执行 Build > Rebuild Project

从命令行:

如果通过命令行 运行 nodes/tests,您需要将以下代码片段添加到每个 CorDapp 模块的 build.gradle 文件中:

tasks.withType(JavaCompile) {
    options.compilerArgs << "-parameters" // Required for shell commands.
}

你可以看一个例子here

正如 Joel 所解释的,默认情况下,已编译的 Java 类 将为其构造函数参数使用默认名称。在 Corda 的情况下,我们应该为参数名称使用相同的名称,不是因为更好地识别它们中的每一个或者它们是如此漂亮以保持相同的名称,而是因为在 AMQP 实现的序列化和反序列化期间有一个验证通过专门为 Corda 定制和重写的组件 (corda-node-api)。该组件检查交易过程中涉及的每个属性(ContractState)。提醒一下,在 Corda 中,所有序列化和反序列化都是受控的,如果有冲突,可能会失败。

要解决这个问题,有不同的形式,这取决于你使用什么工具来自动化编译-gradle,maven等。这是独立于IDE的解决方案( Eclipse、IntelliJ 等)。

Maven - pom.xml

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.7.0</version>
            <configuration>
                <compilerArgs>
                    <arg>-verbose</arg>
                    <arg>-parameters</arg> <!-- To keep parameter names-->
                    <arg>-Xlint:all,-options,-path</arg>
                </compilerArgs>
            </configuration>
        </plugin>

有关传递编译器参数 Maven 的更多信息 https://maven.apache.org/plugins/maven-compiler-plugin/examples/pass-compiler-arguments.html

build.gradle - Gradle

tasks.withType(JavaCompile) {
    options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation" << "-Xlint:-options" << "-parameters"
}

有关编译选项的更多信息Gradle https://docs.gradle.org/current/dsl/org.gradle.api.tasks.compile.CompileOptions.html

您可以在此处查看有关如何设置 compileOptions 的 Whosebug post