web-dev-qa-db-fra.com

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

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

Est-il possible 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 par une sérialisation continue des objets parents. J'ai vu une option de filtrage dans la documentation jackson. Est-ce une solution plausible?

Merci!

96
maverick

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);

Modifier:

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

141
Amir Raminfar

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);
58
laloumen

Utilisation de la classe Java

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

Utiliser l'annotation

@JsonIgnoreProperties(ignoreUnknown=true)
22
Sireesh Yarlagadda

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

@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 ()' ou à peu près (ce qui est le cas pour beaucoup de frameworks)

8
StaxMan

L'approche basée sur l'annotation est meilleure. Mais parfois, le fonctionnement manuel est nécessaire. Pour cela, vous pouvez utiliser sans méthode de 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);
7
Fırat KÜÇÜK

J'avais 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 de manière programmatique, en fonction de la vue à laquelle je m'occupais. Si vous ne pouvez pas faire cela, vous vous retrouvez avec des noms StackOverflowExceptions. 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 par programme ignorer le champ parent de B si je regardais A et ignorer le champ children de A si je regardais B.

J'ai commencé par utiliser mixins pour le faire, 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 à l'aide d'appariements génériques:

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

Dans mon cas initial, le besoin de vues simples comme celle-ci était de montrer le strict minimum sur le parent/enfant, mais cela devenait également utile pour notre sécurité basée sur les rôles. Des vues moins privilégiées des objets sont 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 qu'il puisse correctement gérer ces cas, j'ai écrit une intégration que vous pouvez intégrer 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 aidera quelqu'un d'autre, c'est un problème particulièrement vilain avec Jackson qui n'a pas eu de bonne solution pour mon cas.

5
monitorjbl

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

    @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;
        }
    });
0
fifman

Un autre point positif ici consiste à utiliser @JsonFilter. Quelques détails ici http://wiki.fasterxml.com/JacksonFeatureJsonFilter

0