Jackson - JsonMappingException (Aucun sérialiseur trouvé pour la classe)

Jackson - JsonMappingException (Aucun sérialiseur trouvé pour la classe)

1. Vue d'ensemble

Dans ce rapide tutoriel, nous analyserons le marshalling d'entités sans getters etthe solution for the Jackson JsonMappingException exception.

Si vous voulez creuser plus profondément et apprendreother cool things you can do with the Jackson 2 - allez àthe main Jackson tutorial.

Lectures complémentaires:

Introduction à l'ObjectMapper de Jackson

L'article traite de la classe ObjectMapper centrale de Jackson, de la sérialisation et de la désérialisation de base, ainsi que de la configuration des deux processus.

Read more

Utilisation de facultatif avec Jackson

Un aperçu rapide de la manière dont nous pouvons utiliser l’option en option avec Jackson.

Read more

Spring JSON-P avec Jackson

Cet article explique comment utiliser le nouveau support JSON-P dans Spring 4.1.

Read more

2. Le problème

Par défaut, Jackson 2 ne fonctionnera qu'avec des champs qui sont publics ou qui ont une méthode getter publique -serializing an entity that has all fields private or package private will fail:

public class MyDtoNoAccessors {
    String stringValue;
    int intValue;
    boolean booleanValue;

    public MyDtoNoAccessors() {
        super();
    }

    // no getters
}
@Test(expected = JsonMappingException.class)
public void givenObjectHasNoAccessors_whenSerializing_thenException()
  throws JsonParseException, IOException {
    String dtoAsString = new ObjectMapper().writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, notNullValue());
}

Lefull exception est:

com.fasterxml.jackson.databind.JsonMappingException:
No serializer found for class dtos.MyDtoNoAccessors
and no properties discovered to create BeanSerializer
(to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) )

3. La solution

La solution évidente consiste à ajouter des accesseurs pour les champs - si l'entité est sous notre contrôle. Si ce n'est pas le cas etmodifying the source of the entity is not possible - alors Jackson nous propose quelques alternatives.

3.1. Détection automatique globale des champs avec n'importe quelle visibilité

Une première solution à ce problème consiste à configurer globalement lesObjectMapper pour détecter tous les champs, quelle que soit leur visibilité:

objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

Cela fonctionneraallow the private and package private fields to be detected sans getters, et la sérialisation fonctionnera correctement:

@Test
public void givenObjectHasNoAccessors_whenSerializingWithAllFieldsDetected_thenNoException()
  throws JsonParseException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
    String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
}

3.2. Détecté tous les champs au niveau de la classe

Une autre option fournie par Jackson 2 est - au lieu de la configuration globale -control the field visibility at the class level via l'annotation@JsonAutoDetect:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
public class MyDtoNoAccessors { ... }

Avec cette annotation, la sérialisation devrait maintenant fonctionner correctement avec cette classe particulière:

@Test
public void givenObjectHasNoAccessorsButHasVisibleFields_whenSerializing_thenNoException()
  throws JsonParseException, IOException {
    ObjectMapper objectMapper = new ObjectMapper();
    String dtoAsString = objectMapper.writeValueAsString(new MyDtoNoAccessors());

    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
}

4. Conclusion

Cet article a illustré commentget around the default field visibility in Jackson, en configurant une visibilité personnalisée soit globalement sur lesObjectMapper soit sur des classes individuelles. Jackson permet une personnalisation encore plus poussée en fournissant des options permettant de contrôler avec précision la manière dont le mappeur voit les getters, les setters ou les champs ayant une visibilité spécifique.

L'implémentation de tous ces exemples et extraits de codecan be found in my github project - il s'agit d'un projet basé sur Eclipse, il devrait donc être facile à importer et à exécuter tel quel.