web-dev-qa-db-fra.com

Sérialisation Jackson JSON, évitement de récursivité par définition de niveau

J'utilise la bibliothèque Jackson pour la sérialisation de mes objets pojo en représentation JSON. Par exemple, j'ai la classe A et la classe B:

class A {
  private int id;
  private B b;

  constructors...
  getters and setters
}

class B {
  private int ind;
  private A a;

  constructors...
  getters and setters
}

Si je veux sérialiser un objet de la classe A, il y a une certaine possibilité d'obtenir une récursivité pendant qu'il est sérialisé. Je sais que je peux l'arrêter en utilisant @JsonIgnore.

Est-il possible de limiter la sérialisation par niveau de profondeur?

Par exemple, si le niveau est 2, la sérialisation se fera de cette façon:

  • sérialiser un, niveau = 0 (0 <2 ok) -> sérialiser
  • sérialiser a.b, niveau = 1 (1 <2 ok) -> sérialiser
  • sérialiser a.b.a, niveau = 2 (2 <2 pas vrai) -> stop

Merci d'avance.

30
Goran Nastov

J'ai récemment rencontré un problème similaire: Jackson - sérialisation d'entités avec des relations bidirectionnelles (évitant les cycles)

La solution consiste donc à mettre à niveau vers Jackson 2.0 et à ajouter aux classes l'annotation suivante:

@JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, 
                  property = "@id")
public class SomeEntityClass ...

Cela fonctionne parfaitement.

22
Eugene Retunsky

Vérifiez les liens suivants, cela pourrait vous aider:

La seule option après cela serait de créer votre propre module personnalisé pour la sérialisation/désérialisation pour votre type d'objet. vois ici:

Cordialement.

13
Farid

Il n'y a pas de support pour les ignorants basés sur le niveau.

Mais vous pouvez demander à Jackson de gérer les références cycliques avec 2.0, voir par exemple " Jackson 2.0 publié " pour des explications sur l'utilisation de @JsonIdentityInfo.

4
StaxMan

Pour une sérialisation en profondeur, vous pouvez vous référer à l'exemple ici https://github.com/abid-khan/depth-wise-json-serializer

2
Abid

Si vous voulez vous limiter à un seul niveau (c'est-à-dire: vous allez aux enfants de l'objet courant et pas plus loin), il existe une solution simple avec @JsonView.

Sur chaque champ qui est un lien vers un autre objet, annotez-le avec la classe actuelle comme vue:

class A {
  private int id;
  @JsonView(A.class) private B b;

  constructors...
  getters and setters
}

class B {
  private int ind;
  @JsonView(B.class) private A a;

  constructors...
  getters and setters
}

Ensuite, lors de la sérialisation, utilisez la classe d'objets comme vue. La sérialisation d'une instance de A rendrait quelque chose comme ça:

{
  id: 42,
  b: {
    id: 813
  }
}

Assurez-vous que DEFAULT_VIEW_INCLUSION est défini sur true, sinon les champs sans annotation @JsonView ne seront pas rendus. Vous pouvez également annoter tous les autres champs avec @JsonView à l'aide de la classe Object ou de toute super-classe courante:

class A {
  @JsonView(Object.class) private int id;
  @JsonView(A.class) private B b;

  constructors...
  getters and setters
}
2
Gaël Renoux

Dans certains cas, vous pouvez limiter la profondeur de sérialisation à l'aide d'un entier local de thread contenant une profondeur maximale. Voir ceci réponse .

0
Vjeko

Après plusieurs mois et beaucoup de recherches, j'ai implémenté ma propre solution pour garder mon domaine à l'abri des dépendances jackson.

public class Parent {
    private Child child;
    public Child getChild(){return child;} 
    public void setChild(Child child){this.child=child;}
}

public class Child {
    private Parent parent;
    public Child getParent(){return parent;} 
    public void setParent(Parent parent){this.parent=parent;}
}

Tout d'abord, vous devez déclarer chacune de vos entités de la relation bidirectionnelle dans quelque chose comme ceci:

public interface BidirectionalDefinition {

    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=Parent.class)
    public interface ParentDef{};

    @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id", scope=Child.class)
    public interface ChildDef{};

}

Après cela, le mappeur d'objets peut être configuré automatiquement:

ObjectMapper om = new ObjectMapper();
Class<?>[] definitions = BidirectionalDefinition.class.getDeclaredClasses();
for (Class<?> definition : definitions) {
    om.addMixInAnnotations(definition.getAnnotation(JsonIdentityInfo.class).scope(), definition);
}
0
Pablo