web-dev-qa-db-fra.com

Sérialisation Jackson: comment ignorer les propriétés de la superclasse

Je veux sérialiser une classe POJO qui n'est pas sous mon contrôle, mais je veux éviter de sérialiser toutes les propriétés qui proviennent de la superclasse, et non de la classe finale. Exemple:

public class MyGeneratedRecord extends org.jooq.impl.UpdatableRecordImpl<...>,
    example.generated.tables.interfaces.IMyGenerated {
  public void setField1(...);
  public Integer getField1();

  public void setField2(...);
  public Integer getField2();
...
}

Vous pouvez deviner à partir de l'exemple que cette classe est générée par JOOQ et hérite d'une classe de base complexe UpdatableRecordImpl qui a également des méthodes de type propriété de bean, qui causent des problèmes pendant la sérialisation. De plus, j'ai plusieurs classes similaires, il serait donc bon d'éviter de dupliquer la même solution pour tous mes POJO générés.

Jusqu'à présent, j'ai trouvé les solutions possibles suivantes:

  • ignorer les champs spécifiques provenant de la superclasse en utilisant la technique de mixage comme ceci: Comment puis-je dire à jackson d'ignorer une propriété dont je n'ai pas le contrôle sur le code source?

    Le problème avec cela est que si la classe de base change (par exemple, une nouvelle méthode getAnything () y apparaît), elle peut casser mon implémentation.

  • implémentez un sérialiseur personnalisé et gérez-y le problème. Cela me semble un peu exagéré.

  • comme d'ailleurs j'ai une interface qui décrit exactement les propriétés que je veux sérialiser, peut-être que je peux mélanger une annotation @JsonSerialize (as = IMyGenerated.class) ...? Puis-je l'utiliser pour mon but?

Mais, du point de vue de la conception pure, le mieux serait de pouvoir dire à jackson que je veux sérialiser uniquement les propriétés de la classe finale et ignorer toutes les propriétés héritées. Y-a-t-il un moyen de faire ça?

Merci d'avance.

26
Ferenc

Vous pouvez enregistrer un intropecteur d'annotation Jackson personnalisé qui ignorerait toutes les propriétés provenant d'un certain super type. Voici un exemple:

public class JacksonIgnoreInherited {

    public static class Base {
        public final String field1;

        public Base(final String field1) {
            this.field1 = field1;
        }
    }

    public static class Bean extends Base {
        public final String field2;

        public Bean(final String field1, final String field2) {
            super(field1);
            this.field2 = field2;
        }
    }

    private static class IgnoreInheritedIntrospector extends JacksonAnnotationIntrospector {
        @Override
        public boolean hasIgnoreMarker(final AnnotatedMember m) {
            return m.getDeclaringClass() == Base.class || super.hasIgnoreMarker(m);
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        final ObjectMapper mapper = new ObjectMapper();
        mapper.setAnnotationIntrospector(new IgnoreInheritedIntrospector());
        final Bean bean = new Bean("a", "b");
        System.out.println(mapper
                        .writerWithDefaultPrettyPrinter()
                        .writeValueAsString(bean));
    }

}

Production:

{"field2": "b"}

20
Alexey Gavrilov

Vous pouvez remplacer les méthodes de la superclasse que vous souhaitez empêcher de sortir et les annoter avec @JsonIgnore. La substitution déplace le contrôle de la création de propriété vers la sous-classe tout en permettant sa capacité à la filtrer à partir de la sortie.

Par exemple:

public class SomeClass {
  public void setField1(...);
  public Integer getField1();

  public void setField2(...);
  public Integer getField2();

  @Override
  @JsonIgnore
  public String superClassField1(...){
      return super.superClassField1();
  };

  @Override
  @JsonIgnore
  public String superClassField2(...){
      return super.superClassField2();
  };
...
}
11
ethesx

La bonne utilisation de l'héritage est que les classes enfants étendent ou ajoutent des fonctionnalités. La manière habituelle est donc de sérialiser les données.

Une solution de contournement consisterait à utiliser un objet de valeur (VO) ou un objet de transfert de données (DTO) avec les champs dont vous avez besoin pour sérialiser. Pas:

  • Créez une classe VO avec les champs qui doivent être sérialisés.
  • Utilisez BeanUtils.copyProperties (VO cible, données source) pour copier les propriétés
  • Sérialiser l'instance VO.
2
jordiburgos

Vous pouvez également l'utiliser au lieu de remplacements inutiles

@JsonIgnoreProperties({ "aFieldFromSuperClass"})
public class Child extends Base {
   private String id;       
   private String name; 
   private String category;
} 
0
Ismail Sahin