在Kotlin中,Jackson反序列化错误与数据类

时间:2023-01-28 18:02:56

Not really sure how best to explain the problem so I whipped up the same code as both java and kotlin to better demonstration.

不太确定如何最好地解释这个问题所以我掀起了与java和kotlin相同的代码来更好地演示。

When I read JSON, it appears that it is forcing a data beans value to be NULL even though the parameter is not even part of the json to start with and the data bean defaults the value of the missing field. In java it works correctly never attempting to nullify the value that was never provided to start with. In Kotlin it seems to break because it tries to nullify a non-nullable field.

当我读取JSON时,它似乎强制数据bean值为NULL,即使该参数甚至不是json的一部分,并且数据bean默认缺少字段的值。在java中它正常工作,从不试图使从未提供的值无效。在Kotlin中它似乎打破了,因为它试图使一个不可空的字段无效。

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

Which throws an exception of

这引发了例外

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

In Java (everything works fine)

在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);
  }
}

Even if I make it a class instead of a data class in kotlin, it still errors out the same way.

即使我把它变成了一个类而不是kotlin中的数据类,它仍然会以同样的方式出错。

My question is, how can I get the Jackson deserialization to work in Kotlin with my POJO's. The expected behavior is that it "should" break if a null/incorrect value is passed in for something where null is not allowed. But in the scenario above where no attempt at all was made to change the ts field to a null, it should have used the default value like it does with java.

我的问题是,我怎样才能让杰克逊反序列化与我的POJO一起在Kotlin中工作。预期的行为是,如果为不允许null的内容传入null /不正确的值,它“应该”中断。但是在上面没有尝试将ts字段更改为null的情况下,它应该像使用java一样使用默认值。

The only thing that crosses my mind that seems to work is to not use the concept of the data bean at all and to write my beans like

我觉得唯一可以解决的问题就是不要使用数据bean的概念,而是像我的bean那样编写

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

But then my .equals does not work and it allows others downstream to manipulate the contents of the list and ts properties when I want them to be read-only.

但是我的.equals不起作用,当我希望它们是只读时,它允许下游的其他人操作列表和ts属性的内容。

2 个解决方案

#1


12  

With the 2.8.0 release of jackson-kotlin-module it:

随着jackson-kotlin模块的2.8.0发布它:

now supports using default values in constructor and creator methods

现在支持在构造函数和创建者方法中使用默认值

The following example depicts the feature:

以下示例描述了该功能:

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


-1  

I think one of your incoming properties are null, so you going to need to place ? after jsonProperty that could be null(in you case this is your date field). You can also use raw String data type for your testing with triple quotes """\unescaped string""" so it should be like this val ts: Date? inside of your data class. And you don't have to redeclare the type. So final answer would be : data class Pojo(val name: String, val age: Int, val list: List<String>, val ts: Date?)

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

#1


12  

With the 2.8.0 release of jackson-kotlin-module it:

随着jackson-kotlin模块的2.8.0发布它:

now supports using default values in constructor and creator methods

现在支持在构造函数和创建者方法中使用默认值

The following example depicts the feature:

以下示例描述了该功能:

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


-1  

I think one of your incoming properties are null, so you going to need to place ? after jsonProperty that could be null(in you case this is your date field). You can also use raw String data type for your testing with triple quotes """\unescaped string""" so it should be like this val ts: Date? inside of your data class. And you don't have to redeclare the type. So final answer would be : data class Pojo(val name: String, val age: Int, val list: List<String>, val ts: Date?)

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