The default Spring JSON configuration will show all the
fields of an object during serialization. Often we would like to return a
subset of an entity’s properties and hide some which are only used internally
such as the id and version. Or perhaps return different properties
depending on who/what is requesting the data.
As Spring uses Jackson for JSON serialization it supports
the Jackson Json annotations. Jackson provides a number of options for
“narrowing” or “filtering” the properties of an entity that gets serialized.
Jackson JsonViews (requires adding @JsonView to entity
classes which pollutes them)
Jackson mix-in (requires extending the entity to specify
@JsonIgnoreProperties)
Jackson Filtering options
Example of using Jackson views and mixin for filtering:
This one creates a new annotation to use with JsonViews but
is a little too involved for my liking as it requires changing some Spring
classes.
This link provides a good demo of Jackson Views and Mixins
Within my SearchController I was returning a SearchSummary
object that referenced a Collector object. However, I didn’t want to return all
the Collector details within the SearchSummary as its not relevant. Shown below
is all I required:
@RequestMapping("/rest/loyalty")
@Controller
public class SearchController {
@JsonIgnoreProperties({"loyaltyId","earnings","id","version"})
private static class CollectorIdOnlyView extends Collector {
// Empty by design
...
}
private final ObjectMapper objectMapper = new ObjectMapper();
private final
MappingJacksonJsonView view = new MappingJacksonJsonView();
public SearchController()
{
objectMapper.getSerializationConfig().addMixInAnnotations(Collector.class,
CollectorIdOnlyView.class);
view.setObjectMapper(objectMapper);
}
@Autowired
private AccountService accountService;
@Autowired
private SearchService searchService;
@RequestMapping(value = "/search/{id}", method =
RequestMethod.GET)
public View getSummary(@PathVariable("id") String id, Model
uiModel) {
Collector collector = accountService.findCollectorById(id);
if(collector == null) {
throw new RuntimeException("Collector Not
Found");
} else {
SearchSummary searchSummary = searchService.getSearchSummary(collector);
uiModel.addAttribute("summary",searchSummary);
return view;
}
}
}
For the filtering I had to create a subclass of my entity to
define the properties I wanted to ignore. (CustomerIdOnlyView).
This is then used to configure the ObjectMapper and View.
The change I had to make to the getSummary method was to
change the return type from SearchSummary to View, add the SearchSummary to the
Model and remove the @ResponseBody annotation.