2012-02-21 8 views
11

¿Es posible determinar de forma selectiva cuándo se utiliza la anotación @JsonFilter en el tiempo de ejecución?@JsonFilter arroja "JsonMappingException: No se puede resolver BeanPropertyFilter"

Recibo la excepción JsonMappingException (ver a continuación) cuando no proporciono el filtro.

Antecedentes:

I aprendido de un recent StackOverflow post que puedo usar @JsonFilter filtrar dinámicamente las propiedades del bean conseguir serializados. Esto funciona genial Después de añadir @JsonFilter("apiFilter") a mi clase de dominio y con la adición de este código en mi servicio JAX-RS (utilizando la aplicación CXF), soy capaz de filtrar dinámicamente las propiedades devueltas por mi API REST:

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

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

El problema ¿Hay diferentes llamadas de servicio en las que no quiero aplicar el filtro? En esos casos, quiero devolver toda la clase de dominio sin filtrar ninguna propiedad. En el caso en que sólo trato de devolver la clase de dominio que estoy recibiendo una excepción de la siguiente manera:

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) 

Respuesta

6

Creo que se podría engañar al escritor filtrada definir un filtro de vacío para serializar los casos en los que desea que todas las propiedades seralized:

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

de esta manera, cuando el motor se ve para el filtro "apiFilter" definido en el @JsonFilter anotation, lo encuentra, pero no tendrá ningún efecto (como se serializar todas las propiedades).

EDITAR Además, se puede llamar al método de fábrica en lugar de writer()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); 

creo que esta última solución es más limpia, y de hecho mejor.

+0

en su ejemplo editado, ¿tendría que incluir el código para verificar qué método de escritura llamar en cada llamada de servicio jax-rs? en algunos métodos de servicio devuelvo un objeto Usuario real en lugar de una Cadena. ¡Muchas gracias por tu comentario! – Justin

+1

bien, tuve la oportunidad de darle una oportunidad. el "truco" que sugirió funciona pero no pude obtener su segunda sugerencia "limpia" para que funcione. en ese caso, sigo recibiendo el error "no FilterProvider configurado". gracias de nuevo. – Justin

+0

@Justin: bueno, IMO es una solución "impura" que resuelve un problema, es mejor que uno "limpio" que no funciona :). Espero que haya ayudado a resolver tu problema. –

18

sé que ya ha sido contestada pero para cualquier newcommers Jackson realidad ha añadido la capacidad de no fallar en los filtros que faltan (JACKSON-650):
sólo tiene que llamar SimpleFilterProvider.setFailOnUnknownId(false) y no te vas a esta excepción.

+0

gracias por su respuesta. esto es útil – Justin

+4

Por supuesto, aún necesita configurar un SimpleFilterProvider incluso si no va a utilizar ningún filtro con el asignador que está utilizando. Oh bien. – Jules

0

Tuve un problema similar al obtener la misma excepción, pero la respuesta aceptada realmente no me ayudó en mi caso. Aquí está la solución que funcionó para mí:

En mi configuración que estaba utilizando una costumbre JacksonSerializer así:

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

Y eso serializador se llevó a cabo de esta manera:

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

El problema con este es decir, que mientras no uses ningún filtro, funciona. También funciona si serializa primitivas, por ejemplo si usa jgen.writeString(..). Si usa filtros, ese código es incorrecto, porque los filtros están almacenados en algún lugar dentro de SerializerProvider, no en el JsonGenerator. Si en ese caso utiliza el jsongenerator directamente, se crea un nuevo SerializerProvider, que no conoce los filtros, internamente. Por lo tanto, en lugar del jgen.writeObject(o) más corto, debe llamar al provider.defaultSerializeValue(o, jgen).Eso asegurará que los filtros no se pierdan y puedan aplicarse.

Cuestiones relacionadas