带有默认值的Kotlin数据类上使用Spring构造函数注释

4
为了使用Spring持久性但保持不可变类型,我已经在我的数据类中添加了PersistenceConstructor注释。这告诉Spring在从数据库加载类时使用该构造函数。 然而,我遇到了让Spring找到构造函数的问题。
data class MyData @PersistenceConstructor constructor(@Id val id: Int? = null, val a:String)

这在我的电脑上百分之百有效,但在部署到Heroku后始终失败。

看起来,通过为参数设置默认值,Kotlin会生成多个构造函数,但问题在于每个构造函数都会应用注释,因此只有运气(或JDK实现特定)选择哪一个Spring会使用。默认值没有参数名称,因此Spring不知道该怎么处理它。

我的真实构造函数比这个更大,如果没有默认值,那将是一种痛苦。是否有办法让注释仅适用于没有默认值的构造函数?


现在Kotlin中存在其他选项,我添加了一个回答,涵盖了@JvmOverloads 添加于M12 - Jayson Minard
实际上,这似乎是JvmOverloads的副作用,因为Kotlin数据类中缺少构造函数参数名称才是真正的问题。 实际上看起来像是Kotlin中的一个错误。 - Alexey Sviridov
2个回答

8
您可以使用 @JvmOverloads 注解,它会自动创建方法的排列组合,供 Java 调用,并利用默认值。
从文档中,这是一个例子:
@JvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") {
    ...
}

将会从Java中看到:

// Java
void f(String a, int b, String c) { }
void f(String a, int b) { } // will default c
void f(String a) { } // will default b and c

您的情况略有不同,因为您有一个默认参数,其后是一个非默认参数。简化您的示例如下:

data class MyData @JvmOverloads constructor(val id: Int? = null, val a:String)

使用Java生成此视图:

// java
MyData(Int id, String a)
MyData(String a)  // defaults id

您可以在Kotlin参考文档中了解更多关于Java调用Kotlin互操作性的内容。


如果您将带有默认值的可选字段标记为 @Transient,则此方法将不起作用。解决方法是手动创建构造函数并添加 @PersistenceConstructor 注释。 - ZZ 5

5

目前我的解决方案是定义两个构造函数。一个是为了让我使用,具有默认值;另一个是为了让Spring使用,没有默认值。

data class MyData @PersistenceConstructor constructor(val a: Int?, val b:String, val c : Collection<Int>) {
  constructor(a: Int? = null, b: String = "", c: Collection<Int> = emptyList()) : this(a,b,c)
}

我不喜欢这个方案,因为它会造成重复,所以这不是我的首选解决方案。


如果没有其他答案,我会将其标记为已接受的解决方案,但仍然对其他更简单的选项感兴趣。 - Lionel Port
1
有一个答案是由 Kotlin 支持的,而不必使用这种解决方法。请参见其他发布的答案。 - Jayson Minard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接