Jackson removendo o JSON de JSON com propriedades desconhecidas

Jackson removendo o JSON de JSON com propriedades desconhecidas

1. Visão geral

Neste artigo, vamos dar uma olhada no processo de desempacotamento com Jackson 2.x - especificamente emhow to deal with JSON content with unknown properties.

Se você quiser se aprofundar e aprender outras coisas legais que você pode fazer com o Jackson - vá parathe main Jackson tutorial.

2. Desmarque um JSON com campos adicionais / desconhecidos

A entrada JSON vem em todas as formas e tamanhos - e na maioria das vezes, precisamos mapeá-la para objetos Java predefinidos com um número definido de campos. O objetivo é simplesmenteignore any JSON properties that cannot be mapped to an existing Java field.

Por exemplo, digamos que precisamos desmarcar JSON para a seguinte entidade Java:

public class MyDto {

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

    // standard constructor, getters and setters
}

2.1. UnrecognizedPropertyException em campos desconhecidos

Tentar desempacotar um JSON com propriedades desconhecidas para esta entidade Java simples levará a umcom.fasterxml.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);
}

Isso falhará com a seguinte exceção:

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

2.2. Lidando com campos desconhecidos noObjectMapper

Agora podemos configurar oObjectMapper completo para ignorar propriedades desconhecidas no JSON:

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

Deveríamos, então, poder ler esse tipo de JSON em uma entidade Java predefinida:

@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. Lidando com campos desconhecidos na classe

We can also mark a single class as accepting unknown fields, em vez de JacksonObjectMapper inteiro:

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

Agora, devemos poder testar o mesmo comportamento de antes - campos desconhecidos são simplesmente ignorados e apenas campos conhecidos são mapeados:

@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. Descomplete um JSON incompleto

Da mesma forma que para campos desconhecidos adicionais, desempacotar um JSON incompleto - um JSON que não contém todos os campos na classe Java - não é um problema com 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. Conclusão

Este artigo abordou a desserialização de um JSON com propriedades adicionais desconhecidas, usando Jackson.

Esta é uma das coisas mais comuns a serem configuradas ao trabalhar com Jackson, já que muitas vezes precisamos demap JSON results of external REST APIs to an internal Java representation das entidades da API.

A implementação de todos esses exemplos e trechos de código pode ser encontrada emmy GitHub project.