【问题标题】:Kotlin generate constructor that sets default values to nulled argumentsKotlin 生成将默认值设置为空参数的构造函数
【发布时间】:2017-08-17 07:52:02
【问题描述】:

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

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

从 Kotlin 调用此函数时,非常简单。我可以简单地使用命名参数语法来做到这一点。从 Java 调用,我必须指定所有值,或者使用 @JvmOverloads 注释,它会生成以下构造函数(除了 kotlin 使用默认值的位掩码生成的构造函数):

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)

现在,如果我想在 Java 中创建一个等效于 User(name="John Doe", userGroups=listOf("admin", "super")User 对象,我无法使用上述构造函数来实现。但是,如果我将val userNumber: Int = -1 放在data 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;
    //...
}

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

编辑

我应该澄清一下,创建一个类似的构造函数是行不通的,显然因为两个签名都会在 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"
        )
    }
}

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

【问题讨论】:

  • 你在使用 jackson-module-kotlin(github.com/FasterXML/jackson-module-kotlin) 吗?我认为它可以处理带有默认参数的构造函数。不过,不确定您对 Java 的看法。也许使用辅助构造函数?
  • 我实际上对 Java 没有问题,只有杰克逊。对于java,你是对的,我可以简单地使用辅助构造函数(从技术上讲,上面的静态方法类似于辅助构造函数)。虽然会结帐jackson-module-kotlin...

标签: kotlin


【解决方案1】:

更好的解决方案是增加库理解 Kotlin 函数的可能性。例如,对于 Jackson,存在 jackson-module-kotlin。有了这个库,我们可以在数据类中使用默认参数。

例子:

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

fun main(args: Array<String>) {
    val objectMapper = ObjectMapper()
            .registerModule(KotlinModule())

    val testUser = User(userNumber = 5, name = "someName")

    val stringUser = objectMapper.writeValueAsString(testUser)
    println(stringUser)

    val parsedUser = objectMapper.readValue<User>(stringUser)
    println(parsedUser)

    assert(testUser == parsedUser) {
        println("something goes wrong")
    }
}

【讨论】:

    【解决方案2】:

    在讨论了一分钟之后,我想我找到了一个可能在这里运行良好的解决方案。只需在同一源文件中定义一个顶级函数,即可构建对象。或许是这样:

    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")
    }
    

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

    User user = UserKt.build_user(null, "Hello", null, "Porterhouse Steak");
    System.out.println(user);
    

    示例输出:

    User(userNumber=-1, name=Hello, userGroups=[], screenName=Porterhouse Steak)
    

    该方法介于构造函数和构造函数之间。它胜过敲定一个成熟的 Builder 对象,并避免您的 data class 因不必要的 Java 互操作胶水代码混乱而混乱。

    更多信息请参见Package Level Functions

    【讨论】:

    • 如果您检查我的问题(编辑部分),这正是我正在做的。我没有一个顶级函数,而是在类中有一个静态函数。这使我可以为杰克逊使用@JsonCreator 进行注释,并且还可以从 Java 中使用它。问题是这会产生大量的冗余,而且我实际上是在重写构造函数,现在我也有责任确保在这两点指定的默认值是相同的。
    • 你不能从主构造函数中删除默认值吗?伴随工厂方法应该是您使用可选参数进行构造的唯一途径。
    猜你喜欢
    • 2016-11-03
    • 2019-08-09
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-10
    相关资源
    最近更新 更多