Kotlin生成构造函数,将默认值设置为无效参数

Roh*_*bhu 10 kotlin

我们来看一个数据类的类:

data class User(
    val userNumber: Int = -1,
    val name: String,
    val userGroups; List<String> = emptyList(),
    val screenName: String = "new-user"
)
Run Code Online (Sandbox Code Playgroud)

从Kotlin调用此函数时,它非常简单.我可以简单地使用命名参数语法来实现.从Java调用,我必须指定所有值,或使用@JvmOverloads注释,它生成以下构造函数(除了kotlin使用bit-mask为默认值生成的构造函数):

User(int userNumber, @NotNull String name, @NotNull List userGroups,
     @NotNull String screenName)
User(int userNumber, @NotNull String name, @NotNull List userGroups)
User(int userNumber, @NotNull String name)
User(@NotNull String name)
Run Code Online (Sandbox Code Playgroud)

现在,如果我想User在Java中创建一个等价的对象,User(name="John Doe", userGroups=listOf("admin", "super")我就无法使用上面的构造函数.但是,如果我val userNumber: Int = -1data class声明中放入最后(构造函数的生成似乎取决于定义可选参数的顺序),我可以这样做.这很好,因为期望kotlin生成所有排列会使某些类严重膨胀.

工具的最大问题就是Jackson根本不起作用,因为他们不知道使用哪个构造函数(而不是像我可以特别注释其中一个生成的构造函数).

那么,有没有办法生成(单)构造函数,如:

User(Integer userNumber, String name, List<String> userGroups, String screenName) {
    this.userNumber = (userNumber == null) ? -1 : userNumber;
    this.userGroups = (userGroups == null) ? Collections.emptyList() : userGroups;
    //...
}
Run Code Online (Sandbox Code Playgroud)

目前我正在使用上述方法,但手动定义我需要它们的构造函数.

编辑

我应该澄清一下,创建一个类似的构造函数不起作用,显然是因为这两个签名都会在JVM上发生冲突.这就是我的意料:

data class User(
    val userNumber: Int = -1,
    val name: String,
    val userGroups; List<String> = emptyList(),
    val screenName: String = "new-user"
) {
    companion object {
        @JvmStatic
        @JsonCreator
        fun constructionSupport(
            @JsonProperty("userNumber") userNumber : Int?,
            @JsonProperty("name") name : String,
            @JsonProperty("userGroups") userGroups : List<String>?,
            @JsonProperty("screenName") screenName : String?
        ) = User(
            userNumber = userNumber ?: -1,
            name = name,
            userGroups = userGroups ?: emptyList(),
            screenName = screenName ?: "new-user"
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

还要注意冗余,我必须为属性写两次默认值.我现在看着它,我怀疑是否存在解决方案.也许这是kapt我的基础项目的一个很好的用例:)

sma*_*day 0

经过一分钟的思考后,我想我找到了一个在这里可能效果很好的解决方案。只需在同一源文件中定义一个顶级函数即可构建该对象。也许像这样:

fun build_user(userNumber: Int?, name: String, userGroups: List<String>?, screenName: String?) : User {
  return User(if(userNumber !== null) userNumber else -1, name, if(userGroups !== null) userGroups else emptyList(),
    if(screenName !== null) screenName else "new-user")
}
Run Code Online (Sandbox Code Playgroud)

然后当你需要它时,你只需从 Java 调用它:

User user = UserKt.build_user(null, "Hello", null, "Porterhouse Steak");
System.out.println(user);
Run Code Online (Sandbox Code Playgroud)

示例的输出:

User(userNumber=-1, name=Hello, userGroups=[], screenName=Porterhouse Steak)
Run Code Online (Sandbox Code Playgroud)

该方法介于构造函数和构建器之间。它胜过锤炼出一个成熟的Builder对象,并且避免了data class不必要的 Java 互操作粘合代码混乱。

有关详细信息,请参阅包级函数。