Comment puis-je dire à Jackson d'ignorer une propriété pour laquelle je n'ai pas de contrôle sur le code source?

112

Pour faire court, une de mes entités a une GeometryCollection qui lève une exception lorsque vous appelez "getBoundary" (le pourquoi de ceci est un autre livre, pour l'instant disons que c'est ainsi que cela fonctionne).

Y a-t-il un moyen de dire à Jackson de ne pas inclure ce getter spécifique? Je sais que je peux utiliser @JacksonIgnore lorsque je possède / contrôle le code. Mais ce n'est pas le cas, jackson finit par atteindre ce point grâce à la sérialisation continue des objets parents. J'ai vu une option de filtrage dans la documentation de jackson. Est-ce une solution plausible?

Merci!

Maverick
la source

Réponses:

168

Vous pouvez utiliser Jackson Mixins . Par exemple:

class YourClass {
  public int ignoreThis() { return 0; }    
}

Avec ce Mixin

abstract class MixIn {
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  
}

Avec ça:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

Éditer:

Grâce aux commentaires, avec Jackson 2.5+, l'API a changé et devrait être appelée avec objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)

Amir Raminfar
la source
1
Et si la propriété est générée par la machine et contient des caractères non pris en charge dans son nom? Comme '@'? JVM le permet, mais pas le compilateur Java. Jackson a-t-il une solution pour cela?
marque
3
Et dans Jackson 2.2 c'estobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
Coray du
Comment ignorer en spécifiant le nom de la propriété au lieu de getter?
Erran Morad
68

Une autre possibilité est que, si vous souhaitez ignorer toutes les propriétés inconnues, vous pouvez configurer le mappeur comme suit:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
laloumen
la source
5
Ce serait formidable si nous pouvions configurer objectMapper pour ignorer uniquement les propriétés spécifiques. c'est-à-dire rapporter l'exception pour tous les champs nouveaux / inconnus sauf disons «mon champ». Quelque chose commemapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27
Notez que cela peut également être configuré sur un lecteur en utilisant without()comme dans:mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens
Je déconseille fortement d'utiliser ce mécanisme. La mentalité "stricte" de Jackson, provoquant des erreurs sur des champs inconnus / non gérés, est l'une de ses forces et correspond bien à la nature statiquement typée / analysée au moment de la compilation de Java. Il est préférable de refuser de gérer un ensemble donné de champs ignorés à la place.
Per Lundberg
26

Utilisation de la classe Java

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

Utilisation de l'annotation

@JsonIgnoreProperties(ignoreUnknown=true)
Sireesh Yarlagadda
la source
11

L'approche basée sur les annotations est meilleure. Mais parfois, une opération manuelle est nécessaire. Pour cela, vous pouvez utiliser sans méthode ObjectWriter .

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);
Fırat KÜÇÜK
la source
9
Cette approche ne fonctionne pas pour moi, mais celle du mixin fonctionne. J'obtiens toujours les propriétés ignorées après la sérialisation. Pourquoi avons-nous des mixins alors que nous avons withoutAttribute ()?
Erran Morad
9

Les annotations de mixage fonctionnent assez bien ici, comme déjà mentionné. Une autre possibilité au-delà de @JsonIgnore par propriété est d'utiliser @JsonIgnoreType si vous avez un type qui ne devrait jamais être inclus (c'est-à-dire si toutes les instances des propriétés GeometryCollection doivent être ignorées). Vous pouvez alors soit l'ajouter directement (si vous contrôlez le type), soit en utilisant un mix-in, comme:

@JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

Cela peut être plus pratique si vous avez beaucoup de classes qui ont toutes un seul accesseur 'IgnoredType getContext ()' (ce qui est le cas pour de nombreux frameworks)

StaxMan
la source
5

J'ai eu un problème similaire, mais il était lié aux relations bidirectionnelles d'Hibernate. Je voulais montrer un côté de la relation et ignorer l'autre par programmation, en fonction du point de vue auquel je traitais. Si vous ne pouvez pas faire cela, vous vous retrouvez avec des méchants StackOverflowException. Par exemple, si j'avais ces objets

public class A{
  Long id;
  String name;
  List<B> children;
}

public class B{
  Long id;
  A parent;
}

Je voudrais ignorer par programme le parentchamp de B si je regardais A, et ignorer le childrenchamp de A si je regardais B.

J'ai commencé par utiliser des mixins pour faire cela, mais cela devient très vite horrible; vous avez tellement de classes inutiles qui existent uniquement pour formater des données. J'ai fini par écrire mon propre sérialiseur pour gérer cela de manière plus propre: https://github.com/monitorjbl/json-view .

Il vous permet de spécifier par programme les champs à ignorer:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

Il vous permet également de spécifier facilement des vues très simplifiées via des correspondances génériques:

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

Dans mon cas d'origine, le besoin de vues simples comme celle-ci était de montrer le strict minimum sur le parent / enfant, mais cela est également devenu utile pour notre sécurité basée sur les rôles. Vues moins privilégiées des objets nécessaires pour renvoyer moins d'informations sur l'objet.

Tout cela provient du sérialiseur, mais j'utilisais Spring MVC dans mon application. Pour lui permettre de gérer correctement ces cas, j'ai écrit une intégration que vous pouvez ajouter aux classes de contrôleurs Spring existantes:

@Controller
public class JsonController {
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() {
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  }
}

Les deux sont disponibles sur Maven Central. J'espère que cela aide quelqu'un d'autre, c'est un problème particulièrement laid avec Jackson qui n'avait pas de bonne solution pour mon cas.

monitorjbl
la source
À quoi sert l'importation Match.match()?
Pasupathi Rajamanickam
2

Si vous souhaitez TOUJOURS exclure certaines propriétés pour n'importe quelle classe, vous pouvez utiliser la setMixInResolverméthode:

    @JsonIgnoreProperties({"id", "index", "version"})
    abstract class MixIn {
    }

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) {
            return MixIn.class;  
        }

        @Override
        public ClassIntrospector.MixInResolver copy() {
            return this;
        }
    });
fifman
la source