@JsonFilter throws "JsonMappingException: не удается разрешить BeanPropertyFilter"
Можно ли выборочно определить, когда аннотация @JsonFilter будет использоваться во время выполнения?
Я получаю исключение JsonMappingException (см. ниже), когда я не предоставляю фильтр.
Фон:
Я узнал из qaru.site/info/135925/..., что я могу использовать @JsonFilter для динамического фильтрации свойств bean, получающих сериализацию. Это отлично работает. Добавив @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)
Ответы
Ответ 1
Я думаю, вы могли бы обмануть фильтрованный писатель, определяющий пустой фильтр сериализации для случаев, когда вы хотите, чтобы все свойства были серализованными:
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.serializeAllExcept(emptySet));
Таким образом, когда движок ищет фильтр apiFilter, определенный в anotation @JsonFilter
, он находит его, но он не будет иметь никакого эффекта (как будет сериализовать все свойства).
ИЗМЕНИТЬ
Кроме того, вы можете вызвать метод factory 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);
Я думаю, что это последнее решение стало более чистым и даже лучше.
Ответ 2
Я знаю, что это уже ответили, но для любых новичков Джексон фактически добавил возможность не пропустить недостающие фильтры (JACKSON-650):
Вам просто нужно позвонить
SimpleFilterProvider.setFailOnUnknownId(false)
, и вы не получите это исключение.
Ответ 3
Для конфигурации Spring Boot/Jackson просто добавьте:
@Configuration
public class JacksonConfiguration {
public JacksonConfiguration(ObjectMapper objectMapper) {
objectMapper.setFilterProvider(new SimpleFilterProvider().setFailOnUnknownId(false));
}
}
Ответ 4
У меня была аналогичная проблема с тем же Исключением, но принятый ответ мне действительно не помог. Здесь решение, которое сработало для меня:
В моей настройке я использовал пользовательский 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)
. Это гарантирует, что фильтры не будут потеряны и могут быть применены.