Jackson Unmarshalling JSON with Unknown Properties – 杰克逊对未知属性的JSON进行解密

最后修改: 2013年 12月 31日

1. Overview

1.概述

In this tutorial, we’re going to take a look at the unmarshalling process with Jackson 2.x, specifically how to deal with JSON content with unknown properties.

在本教程中,我们要看一下Jackson 2.x的解读过程,特别是如何处理具有未知属性的JSON内容

To dig deeper and learn other cool things we can do with Jackson, we can check out the main Jackson tutorial.

要想深入挖掘并了解我们可以用杰克逊做的其他很酷的事情,我们可以查看杰克逊主要教程

2. Unmarshall a JSON With Additional/Unknown Fields

2.取消带有额外/未知字段的JSON

JSON input comes in all shapes and sizes, and most of the time, we need to map it to predefined Java objects with a set number of fields. The goal is to simply ignore any JSON properties that cannot be mapped to an existing Java field.

JSON输入有各种形状和大小,大多数情况下,我们需要将其映射到有一定数量字段的预定义Java对象。我们的目标是简单地忽略任何不能被映射到现有Java字段的JSON属性

For example, say we need to unmarshal JSON to the following Java entity:

例如,假设我们需要将JSON解密到以下Java实体。

public class MyDto {

    private String stringValue;
    private int intValue;
    private boolean booleanValue;

    // standard constructor, getters and setters 
}

2.1. UnrecognizedPropertyException on Unknown Fields

2.1.未知字段的UnrecognizedPropertyException

Trying to unmarshal a JSON with unknown properties to this simple Java Entity will lead to a com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:

试图向这个简单的Java实体解读一个具有未知属性的JSON将导致一个com.fastxml.jackson.databind.exc.UnrecognizedPropertyException

@Test(expected = UnrecognizedPropertyException.class)
public void givenJsonHasUnknownValues_whenDeserializing_thenException()
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = 
        "{"stringValue":"a"," +
        ""intValue":1," +
        ""booleanValue":true," +
        ""stringValue2":"something"}";
    ObjectMapper mapper = new ObjectMapper();

    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);

    assertNotNull(readValue);
}

This will fail with the following exception:

这将失败,出现以下异常。

com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: 
Unrecognized field "stringValue2" (class org.baeldung.jackson.ignore.MyDto), 
not marked as ignorable (3 known properties: "stringValue", "booleanValue", "intValue"])

2.2. Dealing With Unknown Fields Using the ObjectMapper

2.2.使用ObjectMapper处理未知字段

We can now configure the full ObjectMapper to ignore unknown properties in the JSON:

我们现在可以配置完整的ObjectMapper以忽略JSON中的未知属性:

new ObjectMapper()
  .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

We should then be able to read this kind of JSON into a predefined Java entity:

然后,我们应该能够将这种JSON读成一个预定义的Java实体。

@Test
public void givenJsonHasUnknownValuesButJacksonIsIgnoringUnknowns_whenDeserializing_thenCorrect()
  throws JsonParseException, JsonMappingException, IOException {
 
    String jsonAsString = 
        "{"stringValue":"a"," +
        ""intValue":1," +
        ""booleanValue":true," +
        ""stringValue2":"something"}";
    ObjectMapper mapper = new ObjectMapper()
      .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);

    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
    assertThat(readValue.getIntValue(), equalTo(1));
}

2.3. Dealing With Unknown Fields at the Class Level

2.3.在类的层面上处理未知字段

We can also mark a single class as accepting unknown fields, instead of the entire Jackson ObjectMapper:

我们也可以将单个类标记为接受未知字段,而不是整个杰克逊ObjectMapper

@JsonIgnoreProperties(ignoreUnknown = true)
public class MyDtoIgnoreUnknown { ... }

Now we should be able to test the same behavior as before. The unknown fields are simply ignored, and only known fields are mapped:

现在我们应该能够测试与之前相同的行为。未知字段被简单地忽略了,只有已知字段被映射。

@Test
public void givenJsonHasUnknownValuesButIgnoredOnClass_whenDeserializing_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
 
    String jsonAsString =
        "{"stringValue":"a"," +
        ""intValue":1," +
        ""booleanValue":true," +
        ""stringValue2":"something"}";
    ObjectMapper mapper = new ObjectMapper();

    MyDtoIgnoreUnknown readValue = mapper
      .readValue(jsonAsString, MyDtoIgnoreUnknown.class);

    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
    assertThat(readValue.getIntValue(), equalTo(1));
}

3. Unmarshall an Incomplete JSON

3.取消不完整的JSON

Similar to additional unknown fields, unmarshalling an incomplete JSON, a JSON that doesn’t contain all the fields in the Java class, isn’t a problem with Jackson:

与额外的未知字段类似,解读一个不完整的JSON,一个不包含Java类中所有字段的JSON,对Jackson来说并不是一个问题。

@Test
public void givenNotAllFieldsHaveValuesInJson_whenDeserializingAJsonToAClass_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = "{"stringValue":"a","booleanValue":true}";
    ObjectMapper mapper = new ObjectMapper();

    MyDto readValue = mapper.readValue(jsonAsString, MyDto.class);

    assertNotNull(readValue);
    assertThat(readValue.getStringValue(), equalTo("a"));
    assertThat(readValue.isBooleanValue(), equalTo(true));
}

4. Conclusion

4.结论

In this article, we discussed deserializing a JSON with additional, unknown properties using Jackson.

在这篇文章中,我们讨论了使用Jackson对具有额外未知属性的JSON进行反序列化。

This is one of the most common things to configure when working with Jackson, since we often need to map JSON results of external REST APIs to an internal Java representation of the entities of the API.

这是使用Jackson工作时最常见的配置之一,因为我们经常需要将外部REST API的JSON结果映射到API实体的内部Java表示中。

The implementation of all of these examples and code snippets can be found in my GitHub project.

所有这些示例和代码片断的实现都可以在我的GitHub项目中找到。