it-swarm.it

Come posso dire a Jackson di ignorare una proprietà per la quale non ho il controllo del codice sorgente?

Per farla breve, una delle mie entità ha una GeometryCollection che genera un'eccezione quando chiami "getBoundary" (il motivo per cui questo è un altro libro, per ora diciamo che è così che funziona). 

C'è un modo in cui posso dire a Jackson di non includere quel getter specifico? So che posso usare @JacksonIgnore quando possiedo/controllo il codice. Ma questo non è un caso, Jackson finisce per raggiungere questo punto attraverso la serializzazione continua degli oggetti genitore. Ho visto un'opzione di filtraggio nella documentazione di Jackson. È una soluzione plausibile?

Grazie!

96
maverick

Puoi usare Jackson Mixins . Per esempio:

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

Con questo Mixin

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

Con questo:

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

Modificare:

Grazie ai commenti, con Jackson 2.5+, l'API è cambiata e dovrebbe essere chiamata con objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)

141
Amir Raminfar

Un'altra possibilità è, se si desidera ignorare tutte le proprietà sconosciute, è possibile configurare il mapper come segue:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
58
laloumen

Utilizzo della classe Java

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

Utilizzo di annotazione

@JsonIgnoreProperties(ignoreUnknown=true)
22

Le annotazioni mix-in funzionano abbastanza bene qui come già accennato. Un'altra possibilità oltre alla proprietà @JsonIgnore consiste nell'utilizzare @JsonIgnoreType se si dispone di un tipo che non dovrebbe mai essere incluso (ad esempio, se tutte le istanze delle proprietà di GeometryCollection devono essere ignorate). Puoi quindi aggiungerlo direttamente (se controlli il tipo), o usando il mix-in, come:

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

Questo può essere più comodo se si dispone di molte classi che hanno tutte un unico Accessor 'IgnoredType getContext ()' o così (che è il caso di molti framework)

8
StaxMan

L'approccio basato sull'annotazione è migliore. Ma a volte è necessario il funzionamento manuale. A tale scopo è possibile utilizzare without method of 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

Ho avuto un problema simile, ma era legato alle relazioni bidirezionali di Hibernate. Volevo mostrare un lato della relazione e ignorare a livello di codice l'altro, a seconda di quale vista stavo trattando. Se non puoi farlo, finisci con StackOverflowExceptions cattive. Per esempio, se avessi questi oggetti

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

public class B{
  Long id;
  A parent;
}

Vorrei ignorare a livello di codice il campo parent in B se guardassi A, e ignorare il campo children in A se guardassi B.

Ho iniziato a usare mixin per fare questo, ma questo diventa molto presto orribile; ci sono così tante classi inutili in giro che esistono solo per formattare i dati. Ho finito per scrivere il mio serializzatore per gestirlo in un modo più pulito: https://github.com/monitorjbl/json-view

Ti consente di specificare a livello di codice quali campi ignorare:

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

Permette anche di specificare facilmente viste molto semplificate tramite i jolly matcher:

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

Nel mio caso originale, la necessità di viste semplici come questa era di mostrare il minimo indispensabile sul genitore/figlio, ma è diventato anche utile per la nostra sicurezza basata sui ruoli. Viste meno privilegiate degli oggetti necessarie per restituire meno informazioni sull'oggetto.

Tutto questo viene dal serializzatore, ma stavo usando Spring MVC nella mia app. Per riuscire a gestire correttamente questi casi, ho scritto un'integrazione che è possibile inserire nelle classi esistenti del controller Spring:

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

Entrambi sono disponibili su Maven Central. Spero che aiuti qualcun altro là fuori, questo è un problema particolarmente brutto con Jackson che non ha una buona soluzione per il mio caso.

5
monitorjbl

Se si desidera SEMPRE escludere determinate proprietà per qualsiasi classe, è possibile utilizzare il metodo 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 altro buon punto qui è usare @JsonFilter. Alcuni dettagli qui http://wiki.fasterxml.com/JacksonFeatureJsonFilter