2012-02-21 3 views
11

Можно ли выборочно определить, когда аннотация @JsonFilter будет использоваться во время выполнения?@JsonFilter throws «JsonMappingException: не удается разрешить BeanPropertyFilter»

Я получаю исключение JsonMappingException (см. Ниже), когда я не предоставляю фильтр.

фона:

я узнал от recent StackOverflow post, что я могу использовать @JsonFilter динамически фильтровать свойства фасоли получать сериализации. Это отлично работает. После добавления @JsonFilter("apiFilter") в мой класс домена и с добавлением этого кода в моей службы JAX-RS (используя реализацию CXF), я могу динамически фильтровать свойства, возвращаемые мой RESTful API:

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

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

Проблема есть ли разные вызовы службы, где я вообще не хочу применять фильтр. В таких случаях я хочу вернуть весь класс домена без фильтрации каких-либо свойств. В том случае, когда я просто пытаюсь вернуть класс домена я получаю исключение следующим образом:

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) 

ответ

6

Я думаю, вы могли бы обмануть отфильтрованный писатель определения пустого фильтра сериализации для тех случаев, когда вы хотите, чтобы все свойства seralized:

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

Таким образом, когда двигатель ищет «apiFilter» фильтр, заданный в @JsonFilter этой заметки, он находит его, но это не будет иметь никакого эффекта (как будет сериализовать все свойства).

EDIT Кроме того, вы можете вызвать метод фабрики 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); 

Я думаю, что это последнее решение является способ очистки, и в самом деле лучше.

+0

в вашем отредактированном примере, мне нужно будет включить код, чтобы проверить, какой метод записи вызывать в каждом вызове службы jax-rs? в некоторых методах обслуживания я возвращаю фактический объект пользователя, а не строку. Большое спасибо за ваш вклад! – Justin

+1

ОК, у меня был шанс попробовать. «трюк», который вы предлагали, но я не мог заставить ваше второе «более чистое» предложение работать. в этом случае я все еще получаю ошибку «no FilterProvider configuration». еще раз спасибо. – Justin

+0

@ Justin: ну, ИМО «нечистое» обходное решение, которое решает проблему, лучше, чем «чистый», не работающий :). Надеюсь, это помогло решить вашу проблему. –

18

Я знаю, что это уже был дан ответ, но и для любых newcommers Джексон на самом деле была добавлена ​​возможность не потерпеть неудачу на отсутствующих фильтров (JACKSON-650):
Вам просто нужно позвонить SimpleFilterProvider.setFailOnUnknownId(false), и вы не получите это исключение.

+0

Спасибо за ответ. это полезно – Justin

+4

Конечно, вам все равно нужно настроить SimpleFilterProvider, даже если вы не собираетесь использовать фильтрацию вообще с помощью картографа, который вы используете. Ну что ж. – Jules

0

У меня была аналогичная проблема с тем же Исключением, но принятый ответ действительно не помог в моем случае. Вот решение, которое работает для меня:

В моей установке я использовал пользовательские JacksonSerializer так:

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

И сериализатор был реализован следующим образом:

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

Проблема с этим заключается в том, что до тех пор, пока вы не используете какие-либо фильтры, он работает. Он также работает, если вы сериализуете примитивы, например, если вы используете jgen.writeString(..). Если вы используете фильтры, этот код неверен, потому что фильтры хранятся где-то внутри SerializerProvider, а не в JsonGenerator. Если в этом случае вы используете jsongenerator напрямую, новый SerializerProvider, который не знает об фильтрах, создается внутренне. Поэтому вместо более короткого jgen.writeObject(o) вам нужно позвонить provider.defaultSerializeValue(o, jgen).Это гарантирует, что фильтры не будут потеряны и могут быть применены.

Смежные вопросы