Jackson JMS unmarshalling avec propriétés inconnues

Jackson JMS unmarshalling avec des propriétés inconnues

1. Vue d'ensemble

Dans cet article, nous allons jeter un oeil au processus de démarshalling avec Jackson 2.x - en particulier àhow to deal with JSON content with unknown properties.

Si vous voulez creuser plus profondément et apprendre d'autres choses intéressantes que vous pouvez faire avec le Jackson, rendez-vous surthe main Jackson tutorial.

2. Démarquer un JSON avec des champs supplémentaires / inconnus

Les entrées JSON sont disponibles dans toutes les formes et toutes les tailles - et la plupart du temps, nous avons besoin de les mapper à des objets Java prédéfinis avec un nombre défini de champs. Le but est simplement deignore any JSON properties that cannot be mapped to an existing Java field.

Par exemple, supposons que JSON soit dissocié de l'entité Java suivante:

public class MyDto {

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

    // standard constructor, getters and setters
}

2.1. UnrecognizedPropertyException sur les champs inconnus

Essayer de démarseler un JSON avec des propriétés inconnues pour cette simple entité Java conduira à uncom.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);
}

Cela va échouer avec l'exception suivante:

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. Traitement des champs inconnus sur lesObjectMapper

Nous pouvons maintenant configurer lesObjectMapper complets pour ignorer les propriétés inconnues dans le JSON:

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

Nous devrions alors pouvoir lire ce type de JSON dans une entité Java prédéfinie:

@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. Gérer les champs inconnus sur la classe

We can also mark a single class as accepting unknown fields, au lieu de l'intégralité de JacksonObjectMapper:

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

Nous devrions maintenant pouvoir tester le même comportement qu'auparavant: les champs inconnus sont simplement ignorés et seuls les champs connus sont mappés:

@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. Démarrez un JSON incomplet

De la même manière que pour les champs inconnus supplémentaires, la démarshalling d'un JSON incomplet - un JSON qui ne contient pas tous les champs de la classe Java - n'est pas un problème avec 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

Cet article traite de la désérialisation d'un JSON avec des propriétés supplémentaires inconnues, à l'aide de Jackson.

C'est l'une des choses les plus courantes à configurer lorsque vous travaillez avec Jackson, car c'est souvent le cas dont nous avons besoin pourmap JSON results of external REST APIs to an internal Java representation des entités de l'API.

L'implémentation de tous ces exemples et extraits de code se trouve dansmy GitHub project.