Jackson 使用可选字段的默认值反序列化记录

ley*_*ren 5 java json record jackson java-record

假设 JSON 结构具有多个可选字段。通过课程,你可以做类似的事情

    public static final class Foo {
        @JsonProperty("x")
        private int x = 1;

        @JsonProperty("y")
        private int y = 2;

        @JsonProperty("z")
        private int z = 3;
        
    }
Run Code Online (Sandbox Code Playgroud)

它定义了字段的默认值,以防它不存在于提供的 json 中。这也可以用记录来完成吗?

    public record Foo(int x, int y, int z) {

    }
Run Code Online (Sandbox Code Playgroud)

构造函数重载显然不是一个选项,据我所知,无论如何你只能有一个@JsonCreator注释。

自定义反序列化器应该可以解决这个问题,但是有没有其他方法,比如提供一个默认值的注释,以在记录的构造函数中使用,以防 json 中未提供该值?

Eug*_*ene 6

Jackson 不支持定义 null 的默认值。
没有注释来设置默认值。
您只能在 java 类级别设置默认值。 该功能
存在未解决的Jackson 问题。

解决方案是仅定义一个具有属性初始化逻辑的构造函数,以防空值。记录是不可变的,字段填充仅通过构造函数执行。仅在构造函数中,您可以定义记录字段的默认值。

public record Foo(Integer x, Integer y, Integer z) {
    public Foo(Integer x, Integer y, Integer z) {
        this.x = x == null ? 1 : x;
        this.y = y == null ? 2: y;
        this.z = z == null ? 3: z;
    }
}
Run Code Online (Sandbox Code Playgroud)

单元测试:

    @Test
    public void test() throws Exception {
        int xDefault = 1;
        int yDefault = 2;
        int zDefault = 3;

        String json = "{ \"x\": 11, \"y\":22, \"z\":33 }";
        ObjectMapper objectMapper = new ObjectMapper();
        Foo foo = objectMapper.reader().readValue(json, Foo.class);

        Assert.assertEquals(11, (int) foo.x());
        Assert.assertEquals(22, (int) foo.y());
        Assert.assertEquals(33, (int) foo.z());

        String json2 = "{ \"x\": 11, \"y\":22}";
        Foo foo2 = objectMapper.reader().readValue(json2, Foo.class);

        Assert.assertEquals(11, (int) foo2.x());
        Assert.assertEquals(22, (int) foo2.y());
        Assert.assertEquals(zDefault, (int) foo2.z());

        String json3 = "{ }";
        Foo foo3 = objectMapper.reader().readValue(json3, Foo.class);

        Assert.assertEquals(xDefault, (int) foo3.x());
        Assert.assertEquals(yDefault, (int) foo3.y());
        Assert.assertEquals(zDefault, (int) foo3.z());
    }
Run Code Online (Sandbox Code Playgroud)