2012-02-21 17 views
11

È possibile determinare in modo selettivo quando viene utilizzata l'annotazione @JsonFilter in fase di runtime?@JsonFilter genera "JsonMappingException: Impossibile risolvere BeanPropertyFilter"

Ricevo un'eccezione JsonMappingException (vedere di seguito) quando non si fornisce il filtro.

Background:

ho imparato da un recent StackOverflow post che posso usare @JsonFilter per filtrare in modo dinamico le proprietà del bean ottenere serializzato. Funziona alla grande Dopo aver aggiunto @JsonFilter("apiFilter") per la mia classe di dominio e con l'aggiunta di questo codice nel mio servizio JAX-RS (usando l'implementazione CXF), sono in grado di filtrare in modo dinamico le proprietà restituite dal mio RESTful API:

// shortened for brevity 
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties)); 

return mapper.filteredWriter(filters).writeValueAsString(user); 

Il problema ci sono diverse chiamate di servizio in cui non voglio affatto applicare il filtro. In questi casi, voglio restituire l'intera classe del dominio senza filtrare alcuna proprietà. Nel caso in cui cerco solo di restituire la classe di dominio sto ottenendo un'eccezione come segue:

Caused by: org.codehaus.jackson.map.JsonMappingException: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured 

at org.codehaus.jackson.map.ser.BeanSerializer.findFilter(BeanSerializer.java:252) 
at org.codehaus.jackson.map.ser.BeanSerializer.serializeFieldsFiltered(BeanSerializer.java:216) 
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:140) 

risposta

6

Penso che si potrebbe ingannare lo scrittore filtrato definire un filtro Serialize vuoto per i casi in cui si desidera che tutte le proprietà seralized:

FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.serializeAllExcept(emptySet)); 

in questo modo, quando il motore cerca il filtro "apiFilter" definito al @JsonFilter anotation, lo trova, ma non avrà alcun effetto (come sarà serializzare tutte le proprietà).

EDIT Inoltre, è possibile chiamare il metodo factory writer() invece di filteredWriter():

ObjectWriter writer=null; 
if(aplyFilter) { 
    FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties)); 
    writer=mapper.filteredWriter(filters); 
} else { 
    writer=mapper.writer(); 
} 

return writer.writeValueAsString(user); 

penso che quest'ultima soluzione è il modo più pulito, e davvero meglio.

+0

nell'esempio modificato, dovrei includere il codice per verificare quale metodo di scrittura chiamare in ogni chiamata di servizio jax-rs? in alcuni metodi di servizio restituisco un oggetto Utente reale anziché una stringa. molte grazie per il tuo contributo! – Justin

+1

ok, ho avuto la possibilità di fare un tentativo. il "trucco" che hai suggerito funziona, ma non sono riuscito a far funzionare il tuo secondo suggerimento "più pulito". in quel caso ricevo ancora l'errore "no FilterProvider configurato". grazie ancora. – Justin

+0

@Justin: beh, IMO una soluzione "non pulita" che risolve un problema è meglio di una "pulita" che non funziona :). Spero che abbia aiutato a risolvere il tuo problema. –

18

So che è già stato risposto, ma per eventuali newcommers Jackson in realtà ha aggiunto la possibilità di non fallire su filtri mancanti (JACKSON-650):
È solo bisogno di chiamare SimpleFilterProvider.setFailOnUnknownId(false) e non sarà possibile ottenere questa eccezione.

+0

grazie per la tua risposta. questo è utile – Justin

+4

Ovviamente è ancora necessario configurare un SimpleFilterProvider anche se non si sta utilizzando il filtraggio con il mapper che si sta utilizzando. Oh bene. – Jules

0

Ho avuto un problema simile ottenendo la stessa eccezione, ma la risposta accettata non è stata di grande aiuto nel mio caso. Ecco la soluzione che ha funzionato per me:

Nel mio setup Io sto usando un JacksonSerializer personalizzato come questo:

@JsonSerialize(using = MyCustomSerializer.class) 
private Object someAttribute; 

E questo serializzatore è stato implementato in questo modo:

public class MyCustomSerializer extends JsonSerializer<Object> { 
    @Override 
    public void serialize(Object o, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException { 
    if (o != null) { 
     jgen.writeObject(o); 
    } 
    } 
} 

Il problema con questo è che, finché non si usano filtri, funziona. Funziona anche se serializzi le primitive, quindi ad esempio se usi jgen.writeString(..). Se si utilizzano i filtri, tale codice è errato, poiché i filtri sono memorizzati da qualche parte all'interno dello SerializerProvider, non nello JsonGenerator. Se in questo caso si utilizza direttamente il jsongenerator, un nuovo SerializerProvider, che non conosce i filtri, viene creato internamente. Quindi, invece del più breve jgen.writeObject(o) devi chiamare provider.defaultSerializeValue(o, jgen).Ciò garantirà che i filtri non si perdano e possano essere applicati.

Problemi correlati