Java Jackson将空字段反序列化为POJO中的默认空列表

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java Jackson将空字段反序列化为POJO中的默认空列表相关的知识,希望对你有一定的参考价值。

我有一个带有lombok注释的POJO,我的JSON通过Jackson反序列化,如下所示:

@Getter
@ToString
@NoArgsConstructor
@Builder
@AllArgsConstructor
@EqualsAndHashCode
@JsonIgnoreProperties(ignoreUnknown = true)
public class ResponsePOJO {
    @JsonProperty("list-one")
    private List<Object> list1 = Lists.newArrayList;
    @JsonProperty("list-two")
    private List<Object> list2 = Lists.newArrayList;
    @JsonProperty("list-three")
    private List<Object> list3 = Lists.newArrayList;
    @JsonProperty("list-four")
    private List<Object> list4 = Lists.newArrayList;
}

当jackson尝试反序列化仅存在list-one和list-two的响应时,我期望得到的POJO具有属性list3list4作为默认值的空列表,但是它们被反序列化为null

确保所有属性都包含来自反序列化JSON的相应值或空列表(默认分配值)的缺失是什么?

---更新----直到我从Spring 1.3.5升级到1.4.2,这也不是问题,它也将我的Jackson版本从2.6.6升级到2.8.4

答案

问题是你还要添加@Builder。初始化程序将移动到构建器,因为您不希望两次运行代码。

lombok的最新版本(1.16.16+)具有@Stone.Default,您可以使用它来影响该行为。

您可以指示Jackson使用构建器,并使您的对象不可变。 Builder适用于不可变对象。

披露:我是一名lombok开发者。

另一答案

龙目岛的@Builder在这里不是一个直接的问题,因为杰克逊并没有将它用于反序列化。但是,Jackson正在使用带有args的非默认构造函数(如果可用)用于对象实例化。否则它使用非arg构造函数。当您在@AllArgsConstructor上使用ResponsePOJO时,Jackson会创建一个如下所示的构造函数:

public ResponsePOJO(List<Object> list1, List<Object> list2, List<Object> list3, List<Object> list4) {
    this.list1 = list1;
    this.list2 = list2;
    this.list3 = list3;
    this.list4 = list4;
}

当调用此构造函数时,将丢弃您的默认值,并为JSON中不存在的字段分配null

虽然@Builder需要所有参数构造函数,但您没有多少方法可以解决此问题:

  1. 不使用@Builder并删除@AllArgsConstructor - 有时您可能不需要任何这些,但这取决于您的情况
  2. 删除@AllArgsConstructor并创建自定义构建器,它不使用里面的所有参数构造函数,而是使用no-arg构造函数。
  3. 使用@Builder并创建与此类似的自定义所有参数构造函数: public ResponsePOJO(List<Object> list1, List<Object> list2, List<Object> list3, List<Object> list4) { this.list1 = list1 == null ? Lists.newArrayList() : list1; this.list2 = list2 == null ? Lists.newArrayList() : list2; this.list3 = list3 == null ? Lists.newArrayList() : list3; this.list4 = list4 == null ? Lists.newArrayList() : list4; } 在这里,Jackson仍会调用上面的所有参数构造函数,但是如果某些字段不存在或者存在并且为null(如果在某些情况下您可能期望空值,例如对无效的验证,则可能会对您的业务逻辑产生下游影响),它将总是分配空列表。
另一答案

我遇到了类似的问题,使用Jackson(com.fasterxml.jackson)和Lombok的@Builder注释反序列化JSON对象。我能够通过在类中创建一个用@JsonPOJOBuilder注释的空类Builder类来解决这个问题,然后添加一个带有对空类的引用的@JsonDeserialize。你可以找到更多信息here

例如,

@Getter
@ToString
@NoArgsConstructor
@Builder
@AllArgsConstructor
@EqualsAndHashCode
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(builder = ResponsePOJO.TypeBuilder.class)
public class ResponsePOJO {
    @JsonPOJOBuilder(withPrefix = "")
    @JsonIgnoreProperties(ModelUtils.TYPE_INFO_PROPERTY)

   public static class TypeBuilder{}//Empty builder class
                                    //Needed just to apply annotations
                                    //Lombok will fill it in later.

    @JsonProperty("list-one")
    private List<Object> list1 = Lists.newArrayList;
    @JsonProperty("list-two")
    private List<Object> list2 = Lists.newArrayList;
    @JsonProperty("list-three")
    private List<Object> list3 = Lists.newArrayList;
    @JsonProperty("list-four")
    private List<Object> list4 = Lists.newArrayList;
}

以上是关于Java Jackson将空字段反序列化为POJO中的默认空列表的主要内容,如果未能解决你的问题,请参考以下文章

Jackson 将额外字段反序列化为 Map

Jackson 使用枚举键、POJO 值反序列化为 Map

使用 Jackson XmlMapper 将 XML 反序列化为 POJO

如何使用 Jackson 将原始 JSON 反序列化为 Java 对象

Jackson 将日期字符串反序列化为 Long

将空 JSON 数组反序列化为空 TreeMap