Justin
Justin

Reputation: 6251

Spring RestTemplate with Jackson throws "Can not resolve BeanPropertyFilter" when using @JsonFilter

Can I specify the Jackson ObjectMapper that Spring's RestTemplate uses?

I'm not 100% that's what I need to do but see below for details.

Background: With help from this StackOverflow post I added @JsonFilter to my domain class and edited my jax-rs web service (implemented in CXF). I'm now successfully able to dynamically select which domain class fields to return in my RESTful API. So far so good.

I'm using Spring's RestTemplate in my JUnit tests to test my RESTful API. This was working fine until I added @JasonFilter to my domain class. Now I'm getting the following exception:

org.springframework.web.client.ResourceAccessException: I/O error: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured; nested exception is org.codehaus.jackson.map.JsonMappingException: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured

at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453)

rest of stack trace omitted for brevity

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)

I was getting a similar problem on the server side and was able to resolve it (with help from this post) by giving a FilterProvider to the Jackson ObjectMapper as follows:

ObjectMapper mapper = new ObjectMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties));

Can I do something similar on the RestTemplate side? Any ideas of how to solve this issue are appreciated.

Just to be clear, on the client RestTemplate side I do not want to filter the domain object properties at all.

Upvotes: 3

Views: 7577

Answers (2)

BeshEater
BeshEater

Reputation: 152

Just adding to the answer. If you are using TestRestTemplate then you can actually get the underlying RestTemplate class and then modify its MappingJackson2HttpMessageConverter to include your filter:

var jackson2HttpMessageConverter = testRestTemplate.getRestTemplate().getMessageConverters().stream()
        .filter(mc -> mc instanceof MappingJackson2HttpMessageConverter)
        .map(mc -> (MappingJackson2HttpMessageConverter) mc)
        .findFirst()
        .orElseThrow();

jackson2HttpMessageConverter.getObjectMapper().setFilterProvider(
        new SimpleFilterProvider().addFilter("MyFilterName", SimpleBeanPropertyFilter.serializeAll())
);

Upvotes: 0

Justin
Justin

Reputation: 6251

Can I specify the Jackson ObjectMapper that Spring's RestTemplate uses?

I was able to force RestTemplate to use a customized ObjectMapper by doing the following:

ObjectMapper mapper = new ObjectMapper();

// set a custom filter
Set<String> filterProperties = new HashSet<String>();
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.serializeAllExcept(filterProperties));
mapper.setFilters(filters);

MappingJacksonHttpMessageConverter messageConverter = new MappingJacksonHttpMessageConverter();
messageConverter.setObjectMapper(mapper);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(messageConverter);
restTemplate.setMessageConverters(messageConverters);

This website provided example for part of the above code.

Upvotes: 6

Related Questions