java / jackson区分null和unset字段

时间:2017-07-30 06:54:30

标签: java json jackson

我有一个系统,其中显式空字段与JSON中不存在的字段不同。用Java表示杰克逊序列化的最佳方法是什么?

例如,我有一个像

这样的数据对象
class Data {
  public String string;
  public String other;
}

默认情况下,杰克逊序列化空字段,因此new ObjectMapper().writeValueAsString(new Data())会产生{"string":null,"other":null}。但是,我希望这会导致{},因为字段是"未设置。"显然,在java中它们是null,但我正在寻找解决方法。

如果我要new ObjectMapper().wirteValueAsString(new Data(null, null)),我希望 导致{"string":null,"other":null}。只有"字符串"字段导致{"string":"value"}

我现在能想到的唯一方法是为每个字段设置布尔值并使用自定义序列化程序来检查布尔值,但这看起来非常混乱。有更简单的方法吗?

编辑: 这不是关于不序列化空值。如果字段显式设置为null,我想要 null值被序列化。

我想也许我可以使用Optionals和Include.NON_ABSENT,但遗憾的是,这不起作用,因为Jackson将null的可选引用视为与Optional.empty()相同。

4 个答案:

答案 0 :(得分:1)

可以使用包含Include.NON_NULL值的JsonInclude注释

来完成
@JsonInclude(Include.NON_NULL)
class IgnoreNullFields
{
  String someString;
}

仅当someString的值与null

不同时才会包含someString

干杯

答案 1 :(得分:1)

这就是我解决的方法。我的要求类似,我有一个微服务将消息发送给另一微服务。

  • 有时生产者将不知道某些字段的值
  • 有时它想将值设置为null
  • 有时它会有一个值。

生产者代码:

USERNAME

消费者代码:

react-native run-android

行家

// object Mapper
ObjectMapper mapper = new ObjectMapper()
               .registerModule(new Jdk8Module())
               .registerModule(new ParameterNamesModule())
               .registerModule(new JavaTimeModule());


// DTO
@Data
@ToString
@JsonInclude(JsonInclude.Include.NON_NULL)
// employee object in producer
public class PEmployee {
    private Optional<String> name;
    private Optional<Integer> age;
    private Optional<BigDecimal> salary;
    private Optional<Boolean> active;
    private Optional<LocalDate> dateOfJoining;
}

// serialize before sending it
PEmployee emp = new PEmployee();
emp.setActive(Optional.ofNullable(Boolean.FALSE));
emp.setName(Optional.of("Johnson"));
emp.setDateOfJoining(Optional.empty());

// PEmployee(name=Optional[Johnson], age=null, 
//salary=null, active=Optional[false], dateOfJoining=Optional.empty)

String payload = mapper.writeValueAsString(emp);
// {"name":"Johnson","active":false,"dateOfJoining":null}

这样

  • getName()。isPresent()-表示发件人知道一个值
  • getAge()== null-表示发件人未发送任何值
  • !getDateOfJoining()。isPresent()-指示发件人要将其设置为null

答案 2 :(得分:0)

  

如果我要做新的ObjectMapper()。wirteValueAsString(new Data(null,   null)),我希望它导致{&#34;字符串&#34;:null,&#34;其他&#34;:null}

这是ObjectMapper的默认行为,没有任何其他配置。例如。下面是代码片段和输出:

Data data = new Data();
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(data));

{"string":null,"other":null}

现在,如果您只想包含非空字段(或set字段),那么您可以通过两种方式完成:

  • 在课程级别,通过使用@JsonInclude(Include.NON_NULL)注释课程,这仅适用于Data课程
  • ObjectMapper级别,通过设置mapper.setSerializationInclusion(Include.NON_NULL);,这将适用于所有类

完成后,您将获得以下内容:

Data data = new Data("value", null);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(data));

{"string":"value"}

答案 3 :(得分:0)

只有配置杰克逊才能实现这一目标。

您说要区分逻辑设置的null和null,只是默认的初始值。这是您的代码需要处理的事情:如何区分这两种情况。如果你使用的是setter,那么就可以很容易地为每个字段添加true / false标记(你可以使用其他不那么麻烦的方法,但超出了这个问题的范围)。

实现了标志后,请为您的类编写自己的序列化程序,以便适当处理此标志。

在任何情况下,我都不会尝试区分这种&#34; 2种空值&#34;除非你试图对json或类似的东西进行部分更新。明确的空值与隐式空值是有问题的IMO。