Reputation: 1324
Hi I have a requirement to dynamically ignore entity fields in spring data rest response [I know they can be done in a static way by using @JsonIgnore annotation] ideally based on a spring security Role .The role part is still manageable but how to dynamically ignore fields in the json response is a challenge. After some analysis and the docs I think jackson is the way to go as spring data rest does provide jackson customization via jackson modules and mixins http://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.custom-jackson-deserialization .
So I think in jackson api it could be done via @jsonFilter and then suppling the same when the ObjectMapper write the object [more details here http://www.cowtowncoder.com/blog/archives/2011/09/entry_461.html] .
But I am not sure how this could be wired up with Spring data rest (basically the part where I acan inject the filterprovider into spring data rest objectmapper).Let me know if anyone has tried this or someone from the Spring data team has insights .
Will post an answer myself If I am able to achieve the same.
UPDATE
So I figured out that the way to implement custom filtering is through the jackson BeanSerializerModifier .Got great help from @cowtowncoder on twitter .Also helpful reference or holy grails for filtering with jackson http://www.cowtowncoder.com/blog/archives/2011/02/entry_443.html
Upvotes: 4
Views: 5400
Reputation: 438
This example shows how to implement a dynamic JSON transformation (filtering) in a Spring Boot REST controller. It is using AOP controller advice to change controller method output in runtime. Code on github: https://github.com/andreygrigoriev/jsonfilter
@ControllerAdvice
@SuppressWarnings("unused")
public class FilterAdvice implements ResponseBodyAdvice<Object> {
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
String fields = ((ServletServerHttpRequest) request).getServletRequest().getParameter("fields");
return new FilterMappingJacksonValue<>(body, StringUtils.isEmpty(fields) ? new String[] {} : fields.split(","));
}
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
}
public class FilterMappingJacksonValue<T> extends MappingJacksonValue {
public FilterMappingJacksonValue(final T value, final String... filters) {
super(value);
setFilters(new SimpleFilterProvider().addFilter("dynamicFilter",
filters.length > 0 ? SimpleBeanPropertyFilter.filterOutAllExcept(filters) : SimpleBeanPropertyFilter.serializeAll()));
}
}
@Data
@AllArgsConstructor
@JsonFilter("dynamicFilter")
public class Book {
String name;
String author;
}
@RestController
@SuppressWarnings("unused")
public class BookController {
@GetMapping("/books")
public List<Book> books() {
List<Book> books = new ArrayList<>();
books.add(new Book("Don Quixote", "Miguel de Cervantes"));
books.add(new Book("One Hundred Years of Solitude", "Gabriel Garcia Marquez"));
return books;
}
}
Upvotes: 1
Reputation: 1324
So yes finally I was able to solve this .The trick here is to use a custom BeanSerializerModifier and register it via a Custom Module [which is the custom hook available to customize spring data rest jackson serialization],something like
setSerializerModifier( new CustomSerializerModifier()).build()));
now you can customize our BeanSerializerModifier by overriding the method changeProperties to apply your custom filter ,which basically includes and excludes BeanPropertyWriter based on your logic .sample below
List<BeanPropertyWriter> included = Lists.newArrayList();
for (BeanPropertyWriter property : beanProperties)
if (!filter.contains(property.getName()))
included.add(property);
this way you can include any logic per class or otherwise and filter properties form response in a custom manner.Hope It Helps
Also have updated my code on github do look at https://github.com/gauravbrills/SpringPlayground
Upvotes: 5