在Corda中,向状态添加新属性(状态演化)要求新属性为空,以便与该状态的先前版本向后兼容。
data class Version1DummyState(
override val participants: List<AbstractParty>
) : ContractState
data class Version2DummyState(
override val participants: List<AbstractParty>,
val myNewProperty: String? = null
) : ContractState
由于Kotlin还支持具有默认值的属性,所以我想知道为什么状态演化只限于 nullable 类型的属性,而不限于非null的属性,只要这些属性具有默认值?
data class Version2DumyState(
override val participants: List<AbstractParty>,
val myNewProperty: String = "Hello, world."
) : ContractState
我提出此问题的理由来自于查看隐式升级样本,在该样本中,义务状态已升级,以允许债务人违约。 true
和false
准确地表示债务人是否违约,而null
没有。与使用可为空的字段相比,使用默认值false
进行升级的能力似乎更为自然。
答案 0 :(得分:2)
我认为您可以通过用@JvmOverloads
标记构造函数来实现上述目的:
data class DummyState @JvmOverloads constructor(
override val participants: List<AbstractParty>,
val myNewProperty: String = "blah"
) : ContractState
(不要将版本号放入州级名称中)
@JvmOverloads
使反序列化引擎可以看到“旧的”构造函数以进行匹配。
但是,最好在这里用如下代码行来明确:
val inDefault: Boolean get() = myNewProperty ?: false
或
fun priceOr(default: Amount<Currency> = 0.USD) get() = price ?: default
如果您真的想要这个。
向后兼容性和默认值需要非常小心地对待。一个常见的错误是对新引入的字段使用默认值零/空字符串/ false,即使这些值对应用程序在语义上有意义。也就是说,知道旧消息未指定某些内容是有价值的信息,不应丢失或将其替换为脆弱的哨兵值。考虑新的字段“价格”。价格不能为负,因此开发人员可能会将默认值设置为零。但是免费定价是一件有意义的事情-也许不是在当今的业务环境中,还是明天?现在您遇到了问题。
Kotlin的类型系统和语法非常擅长处理缺失值。使用?:
运算符在使用现场替换默认设置非常容易,我担心会建立一个约定,始终在初级开发人员遵循的施工现场提供默认设置,而不会意识到潜在的后果。明确暴露默认值可以替代的事实迫使人们思考这是否真的合乎逻辑。