📜 ⬆️ ⬇️

Spring / Jackson + @JsonView: filtering JSON


Hello!

Recently, in my Spring training project, Java Enterprise (Topjava) faced the task of customizing the serialization of a User object in JSON depending on the controller: for the controller REST API, it was necessary to return the hashed password ( user.password field), but not for the display controller for UI. You can solve the problem in the "forehead" by making a few TO ( Data Transfer Object ), but in Spring 4.2 + / Jackson 2.6 you can use Jackson's Serialization Views . However, there is a trick to the article, and for inattentive readers, views do not work the way they expect.

As a result, I had to dig a little in the implementation of Jackson, to understand how it all works. Briefly about this:
')

MapperFeature.DEFAULT_VIEW_INCLUSION



The article has a slight mention
In Spring MVC default configuration, MapperFeature.DEFAULT_VIEW_INCLUSION is set to false.

This means that by default, fields not marked with the @JsonView annotation @JsonView excluded. But if you look at the MapperFeature code, you will see:

  ... * Default value is enabled, meaning that non-annotated * properties are included in all views if there is no * {@link com.fasterxml.jackson.annotation.JsonView} annotation. * * Feature is enabled by default. */ DEFAULT_VIEW_INCLUSION(true), 

That is, everything is exactly the opposite - everything that is not marked is turned on. And if you mark only the User fields required for the UI:

 public class User ... @JsonView(View.UI.class) protected String email; @JsonView(View.UI.class) protected boolean enabled = true; protected String password; 

and call the controller method labeled @JsonView

 @JsonView(View.UI.class) @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public User get(@PathVariable("id") int id) { return ...; } 

That will result in both marked User fields ( email, enabled, .. ), and all others ( password ).

FilteredBeanPropertyWriter


Since I want to exclude only one password field from the UI controller, it will be logical to flag only it. We look into the code of jackson-databind-2.8.0 : if the controller's request and the fields of its result are annotated @JsonView , Jackson serializes through FilteredBeanPropertyWriter.serializeAsField

  final Class<?> activeView = prov.getActiveView(); if (activeView != null) { int i = 0, len = _views.length; for (; i < len; ++i) { if (_views[i].isAssignableFrom(activeView)) break; } // not included, bail out: if (i == len) { _delegate.serializeAsOmittedField(bean, jgen, prov); return; } } _delegate.serializeAsField(bean, jgen, prov); 

Those. if the View that marks the object field matches or is a superclass from the View method of the controller, the field will be serialized. Otherwise, it is skipped ( serializeAsOmittedField ).

Decision


Eventually:


Now the password field will not fall into the result. In the REST controller, you can do without @JsonView , because all User fields are included there.

Thanks for attention! I hope @JsonView will make your Spring applications more beautiful and compact.

Source: https://habr.com/ru/post/307392/


All Articles