1. 概述

在这个教程中,我们将探讨在使用 Jackson 解析JSON字符串时处理null或缺失值的不同方法。我们将深入研究三种提供不同控制级别的选项。

2. 在类级别设置默认值

首先,我们来看如何在接收的JSON字符串中完全缺失字段时,将默认值放入我们的POJO(Plain Old Java Object)对象。创建一个有两个字段的对象,其中一个为必需,另一个我们将设置默认值:

class NonAnnotatedDefaultValue {
    String required;
    String optional = "defaultValue";
    // Standard getters and setters
}

这里我们在名为optional的字段上分配了一个值。如果JSON中没有这个字段,Jackson将使用这个String值。现在,让我们使用这个对象,让Jackson将一个不包含名为optional字段的JSON字符串映射到对象。我们将使用[ObjectMapper](/jackson-object-mapper-tutorial)对象及其readValue()方法:

@Test
void givenAClassWithADefaultValue_whenReadingJsonWithoutOptionalValue_thenExpectDefaultValueInResult()
  throws JsonProcessingException {
    String noOptionalField = "{\"required\": \"value\"}";
    ObjectMapper objectMapper = new ObjectMapper();
    NonAnnotatedDefaultValue createdObject = objectMapper.readValue(noOptionalField, NonAnnotatedDefaultValue.class);
    assert(createdObject.getRequired()).equals("value");
    assert(createdObject.getOptional()).equals("defaultValue");
}

通过断言,我们可以看到生成的对象既包含了JSON中的值,也包含了我们之前指定的默认值。

这种方法的缺点是,它只适用于JSON中的属性完全缺失的情况。 如果属性存在但值为null,Jackson将不会应用默认值。在接下来的部分,我们将看到更佳的方法来处理null值。

3. 实现setter方法以获取最大控制权

我们可以通过为字段实现setter方法来完全控制映射过程。创建一个具有Jackson用于创建对象所需的必需setter的方法的对象:

class SetterDefaultValue {
   String required;
   String optional = "valueIfMissingEntirely";

    public void setOptional(String optional) {
        if (optional == null) {
            this.optional = "valueIfNull";
        }
    }
   // Standard getters and setters
}

这里我们像以前一样在类级别提供了默认值。然而,我们也提供了setter方法。在setter方法内部,我们现在可以执行任何我们喜欢的操作。在这个例子中,我们明确地提供了当值为null时的预期行为。现在,如果我们不在JSON中包含该属性,Jackson将设置optionalvalueIfMissingEntirely,如果属性存在但设置为null,则设置为valueIfNull

如果我们需要,这两个值可以相同。让我们看看实际操作:

@Test
void givenAClassWithASetter_whenReadingJsonWithNullOptionalValue_thenExpectDefaultValueInResult()
  throws JsonProcessingException {
    String nullOptionalField = "{\"required\": \"value\", \"optional\": null}";
    ObjectMapper objectMapper = new ObjectMapper();
    JsonSetterDefaultValue createdObject = objectMapper.readValue(nullOptionalField, JsonSetterDefaultValue.class);
    assert(createdObject.getRequired()).equals("value");
    assert(createdObject.getOptional()).equals("valueIfNull");
}

这里我们提供了JSON,其中名为optional的字段被设置为null从断言中我们可以看出,Jackson创建的对象中,由于我们的注解,optional字段已设置为valueIfNull这种方法为我们提供了极大的灵活性。如果我们想要,我们也可以检查空String并以相同的方式应用默认值。

4. 使用@JsonSetter与Nulls.SKIP

我们的最后一个选项是使用@JsonSetter并将其扩展以告诉它忽略null值。让我们创建一个新的类:

class NullsSkipDefaultValue {
    private String required;
    @JsonSetter(nulls = Nulls.SKIP)
    private String optional = "defaultValue";
    // standard getters and setters
}

Nulls.SKIP参数告诉@JsonSetter跳过所有null值的输入。然后Jackson将使用提供的默认值。Nulls枚举中还有其他几个选项,例如Nulls.SET会告诉Jackson将JSON中的null转换为POJO中的Java null。今天我们将继续使用Nulls.SKIP

@Test
void givenAClassWithAJsonSetterNullsSkip_whenReadingJsonWithNullOptionalValue_thenExpectDefaultValueInResult() throws JsonProcessingException {
    String nullOptionalField = "{\"required\": \"value\", \"optional\": null}";
    ObjectMapper objectMapper = new ObjectMapper();
    NullsSkipDefaultValue createdObject = objectMapper.readValue(nullOptionalField, NullsSkipDefaultValue.class);
    assert(createdObject.getRequired()).equals("value");
    assert(createdObject.getOptional()).equals("defaultValue");
}

如上所述,对于第3部分中的相同输入JSON(即optional字段被赋值为null),我们得到了我们想要的默认值。如果我们不提供可选字段,这也给出了相同的结果。

5. 总结

在这篇文章中,我们探讨了使用Jackson解析JSON时处理缺失或null值的三种方法。类级别设置值很有用,但如果遇到null值则会失败。我们可以选择实现setter方法以获得最大控制,或者在字段声明上使用@JsonSetter来简单地忽略null值。这三种方法根据我们的具体需求都可能是合适的。最重要的是考虑我们希望应用程序如何处理值为null的属性。

如往常一样,示例的完整代码可以在GitHub上找到。