1. 概述
本教程將探討使用 Jackson 2.x 進行反序列化的過程,特別是 如何處理具有未知屬性的 JSON 內容。
要深入瞭解並學習更多關於 Jackson 的用法,您可以查看 Jackson 的主教程。
2. 解構包含附加/未知字段的 JSON 數據
JSON 輸入數據形式各異,大多數情況下,我們需要將其映射到預定義的 Java 對象,這些對象具有固定的字段數量。目標是簡單地忽略任何無法映射到現有 Java 字段的 JSON 屬性。
例如,假設我們需要將 JSON 解構到以下 Java 實體:
public class MyDto {
private String stringValue;
private int intValue;
private boolean booleanValue;
// standard constructor, getters and setters
}2.1. 未知字段導致的 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException
嘗試將包含未知屬性的 JSON 映射到此簡單的 Java 實體,將會導致 com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException。
@Test(expected = UnrecognizedPropertyException.class)
public void givenJsonHasUnknownValues_whenDeserializingAJsonToAClass_thenExceptionIsThrown()
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);
}這將導致以下異常:
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. 使用 ObjectMapper 處理未知字段
現在,我們可以配置完整的 ObjectMapper 以忽略 JSON 中未知的屬性:
new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)我們應該能夠將這種 JSON 讀取到預定義的 Java 實體中:
@Test
public void givenJsonHasUnknownValuesButJacksonIsIgnoringUnknownFields_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. 處理類級別未知字段
我們也可以將單個類標記為接受未知字段,而不是整個 Jackson 的 ObjectMapper。
@JsonIgnoreProperties(ignoreUnknown = true)
public class MyDtoIgnoreUnknown { ... }現在我們應該能夠測試之前相同的行為。未知的字段會被簡單地忽略,只有已知的字段才會進行映射:
@Test
public void givenJsonHasUnknownValuesButUnknownFieldsAreIgnoredOnClass_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. 解讀不完整 JSON
類似於額外的未知字段,解讀不完整 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. 結論
在本文中,我們討論了使用 Jackson 解序列化包含額外未知屬性的 JSON 的方法。
這在與 Jackson 協作時最常見的情況之一,因為我們經常需要將外部 REST API 的 JSON 結果映射到 API 實體內部的 Java 表示形式。