如何表示“未设置”的 Java 成员,以便可以使用 Jackson 在 JSON 中将它们序列化为未设置

Pan*_*nda 2 java json jackson

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

例如,我有一个像

class Data {
  public String string;
  public String other;
}
Run Code Online (Sandbox Code Playgroud)

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

如果我这样做new ObjectMapper().wirteValueAsString(new Data(null, null)),我想导致{"string":null,"other":null}。并且只有“字符串”字段导致{"string":"value"}.

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

编辑:这不是不序列化空值。如果字段显式设置为空,我希望空值被序列化。

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

man*_*niB 5

我就是这样解决的。我的要求类似于我有一个微服务向另一个微服务发送消息。

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

生产者代码:

// 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}
Run Code Online (Sandbox Code Playgroud)

消费者代码:

// DTO
@Data
@ToString
public class CEmployee {
    private Optional<String> name;
    private Optional<Integer> age;
    private Optional<BigDecimal> salary;
    private Optional<Boolean> active;
    private Optional<LocalDate> dateOfJoining;
}

// deserialize
CEmployee emp = mapper.readValue(payload, CEmployee.class);

// CEmployee(name=Optional[Johnson], age=null, 
// salary=null, active=Optional[false], dateOfJoining=Optional.empty)
Run Code Online (Sandbox Code Playgroud)

马文

    <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-parameter-names</artifactId>
        <version>2.8.10</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jdk8</artifactId>
        <version>2.8.10</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-jsr310</artifactId>
        <version>2.8.10</version>
    </dependency>
Run Code Online (Sandbox Code Playgroud)

这边走

  • getName().isPresent() - 表示发送者知道一个值
  • getAge() == null - 表示发送者没有发送任何值
  • !getDateOfJoining().isPresent() - 表示发件人希望将其设置为空