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


112

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

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

Grazie!

Risposte:


168

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)


1
E se la proprietà è generata dalla macchina e ha caratteri non supportati nel nome? Piace '@'? JVM lo consente, ma il compilatore Java no. Jackson ha una soluzione per questo?
segna il

3
E in jackson 2.2 èobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

Come faccio a ignorare specificando il nome della proprietà invece di getter?
Erran Morad

68

Un'altra possibilità è che, se vuoi ignorare tutte le proprietà sconosciute, puoi configurare il mapper come segue:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
Sarebbe fantastico se potessimo configurare objectMapper per ignorare solo le proprietà specifiche. cioè riporta l'eccezione per tutti i campi nuovi / sconosciuti eccetto diciamo 'miocampo'. Qualcosa comemapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27

Si noti che questo può essere configurato anche su un lettore utilizzando without()come in:mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens

Sconsiglio vivamente di utilizzare questo meccanismo. La mentalità "rigida" di Jackson, che causa la generazione di errori su campi sconosciuti / non gestiti, è uno dei suoi punti di forza e corrisponde bene alla natura di Java analizzata in fase di compilazione e tipizzata staticamente. È molto meglio invece rinunciare alla gestione di un determinato insieme di campi ignorati.
Per Lundberg,

26

Utilizzando Java Class

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

Utilizzo dell'annotazione

@JsonIgnoreProperties(ignoreUnknown=true)

11

L'approccio basato sull'annotazione è migliore. Ma a volte è necessaria l'operazione manuale. A tale scopo è possibile utilizzare senza metodo 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);

9
Questo approccio non funziona per me, ma quello di mixin sì. Ottengo ancora le proprietà ignorate dopo la serializzazione. Perché abbiamo mixin quando abbiamo withoutAttribute ()?
Erran Morad

9

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

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

Questo può essere più conveniente se hai molte classi che hanno tutte una singola funzione di accesso 'IgnoredType getContext ()' o giù di lì (che è il caso di molti framework)


5

Ho avuto un problema simile, ma era correlato alle relazioni bidirezionali di Hibernate. Volevo mostrare un lato della relazione e ignorare a livello di programmazione l'altro, a seconda di quale punto di vista avevo a che fare. Se non puoi farlo, finisci con le cattive StackOverflowExceptions. Ad esempio, se avessi questi oggetti

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

public class B{
  Long id;
  A parent;
}

Vorrei ignorare programmaticamente il parentcampo in B se guardassi A e ignorare il childrencampo in A se guardassi B.

Ho iniziato a usare i mixin per farlo, ma molto rapidamente diventa orribile; hai così tante classi inutili che esistono solo per formattare i dati. Ho finito per scrivere il mio serializzatore per gestirlo in 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")));

Consente inoltre di specificare facilmente visualizzazioni molto semplificate tramite corrispondenze di caratteri jolly:

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

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

Tutto questo proviene dal serializzatore, ma stavo usando Spring MVC nella mia app. Per far sì che gestisca correttamente questi casi, ho scritto un'integrazione che puoi inserire nelle classi di controller Spring esistenti:

@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 aveva una buona soluzione per il mio caso.


A cosa serve l'importazione Match.match()?
Pasupathi Rajamanickam

2

Se vuoi SEMPRE escludere certe proprietà per qualsiasi classe, puoi usare il setMixInResolvermetodo:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.