在Kotlin中,数据类使用Jackson反序列化时出现错误

7

我不太确定如何最好地解释这个问题,所以我写了同样的Java和Kotlin代码来更好地演示。

当我读取JSON时,它似乎强制将数据bean值设为NULL,即使该参数根本不是JSON的一部分,并且数据bean默认缺失字段的值。在Java中,它可以正确地工作,从未尝试将从未提供的值变为空值。但在Kotlin中,它似乎会出现问题,因为它试图使非空字段为空。

在Kotlin中

data class Pojo(val name: String, val age: Int, val list: List<String> = emptyList(), val ts: Date = Date())

private val mapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule())
    .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)

fun main(args: Array<String>) {
    mapper.readValue("""{"name": "John Doe", "list": ["yellow", "green"], "age": 42}""", Pojo::class.java)
}

这会抛出一个异常:

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method Pojo.<init>, parameter ts

在Java中(一切都运作良好)
public class Transform {
  private static ObjectMapper mapper = new ObjectMapper()
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

  public static class Pojo {
    private String name;
    private int age;
    private List<String> list;
    private Date ts = new Date();
    <getters and setters for all>
  }

  public static void main(String[] args) throws IOException {
    String json = "{\"name\": \"John Doe\", \"list\": [\"yellow\", \"green\"], \"age\": 42}";
    Pojo p = mapper.readValue(json, Pojo.class);
    System.out.printf("Bean: name=%s, age=%s, list=%s, ts=%s\n", p.name, p.age, p.list, p.ts);
  }
}

即使我在Kotlin中将其作为类而不是数据类,它仍然以同样的方式出错。
我的问题是,如何在Kotlin中使用我的POJO使Jackson反序列化工作。期望的行为是,如果传递了空/不正确的值,它“应该”中断。但在上述情况下,在根本没有尝试将ts字段更改为null的情况下,它应该像Java一样使用默认值。
唯一让我想到并且似乎起作用的事情是根本不使用数据bean的概念,并像这样编写我的bean:
class Pojo(val name: String, val age: Int) {
    var list: List<String> = emptyList()
    var ts: Date = Date()
}

但是,我的 .equals 方法不起作用,并且它允许下游用户操纵列表的内容和 ts 属性,而我希望这些属性只读。

2个回答

15

随着2.8.0版本的发布,jackson-kotlin-module现在支持在构造函数和创建者方法中使用默认值。

以下示例演示了该功能:

data class Question(val title: String = "Is programming hard?", val answer: String)

val q = mapper.readValue<Question>("""{"answer": "Sure it can be"}""")
println(q) //-> Question(title=Is programming hard?, answer=Sure it can be)

2
正确,这个变更是2.8.x版本的新功能,无法向早期版本回溯,因此您必须升级,因为Jackson显式地添加了新的API以给插件模块更多的控制权。 - Jayson Minard
谢谢,这解决了问题。我一开始使用的是2.7.5,当时它是最新版本。从来没有想过我只需要升级库就行了。很高兴有一个简单的解决方案。 - Ryba

-1

我认为你的某个传入属性为空,所以你需要在可能为空的jsonProperty后面放置?(在你的情况下是日期字段)。你也可以使用原始字符串数据类型进行测试,用三重引号"""\未转义字符串"""。这样应该像这样:val ts:Date?在你的数据类中。而且你不必重新声明类型。所以最终答案应该是:data class Pojo(val name: String, val age: Int, val list: List<String>, val ts: Date?)


1
他询问了一个情况,其中他对参数有一个默认值,从Jackson 2.8.0开始(正如Miensol所提到的),这个情况可以很好地处理。而且该版本的空值处理也更加智能。如果他使用2.8.0,他将没有任何问题。 - Jayson Minard

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