Spring MVC 4 REST + Jackson @JsonView Annotation Integration Example
July 05, 2016
This page will walk through Spring MVC 4 REST and Jackson @JsonView annotation integration example. @JsonView is used to filter JSON response. Spring 4.1 framework and onwards started to support Jackson @JsonView
annotation directly. To work with @JsonView
, first we need to define view definition. We can have more than one view definition. One view definition can inherit other view definition. Our POJO will be annotated with @JsonView
by passing defined view as an attribute. In spring controller we can directly annotate our methods with Jackson @JsonView
annotation. The JSON response will be filtered on the basis of configured view while serializing HTTP response body. We can also use spring REST client with @JsonView
. Spring provides MappingJacksonValue
that wraps the POJO and by setting serialization view, we can filter the JSON being sent to web service server using RestTemplate
. Now find the complete example step by step.
Contents
- Software Requirement
- Project Structure in Eclipse
- Gradle File with Spring Boot
- Create JSON View Definition
- Create POJO Using Jackson @JsonView Annotation
- Create Spring MVC Controller with @JsonView Annotation
- Create Java Configuration and Application Initializer
- Run Application
- Spring REST Client with @JsonView using MappingJacksonValue
- Download Complete Source Code
Software Requirement
Find the required software to run the demo.1. Java 8
2. Spring 4.2.6.RELEASE
3. Jackson 2.6.6
4. Tomcat 8
5. Gradle
6. Eclipse
Project Structure in Eclipse
Find the project structure in eclipse.Gradle File with Spring Boot
Find the gradle file used in our example. We are using spring boot that will import all the required JAR dependencies of Spring and Jackson API.build.gradle
apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'war' archivesBaseName = 'spring-rest' version = '1' repositories { mavenCentral() } dependencies { compile 'org.springframework.boot:spring-boot-starter-web:1.3.5.RELEASE' }
Create JSON View Definition
The object can be contextually filtered while serializing HTTP response using@JsonView
. The first step to use @JsonView
, we need to create JSON view definitions. We need to create interfaces or static classes. For more than one view we can create more than one interface. It is better to create composite interfaces. Create more than interface within a class for more than one serialized view as HTTP response. To inherit one view by other, we need to inherit one interface by other.
Profile.java
package com.concretepage; public class Profile { public interface PublicView {} public interface FriendsView extends PublicView{} public interface FamilyView extends FriendsView {} }
Create POJO Using Jackson @JsonView Annotation
Jackson provides the annotationcom.fasterxml.jackson.annotation.JsonView
that needs to be annotated on class properties to include in a specific JSON view serialized in HTTP response body. We have three views here in our example i.e PublicView
, FriendsView
and FamilyView
. The properties annotated with @JsonView
will take part in filtering JSON views.
1. In user public profile view, only those class properties will be available which are annotated with
@JsonView(Profile.PublicView.class)
.
2. In user friends profile view, the class properties will be available which are annotated with
@JsonView(Profile.PublicView.class)
and @JsonView(Profile.FriendsView.class)
.
3. In user family profile view the properties will be available which are annotated with
@JsonView(Profile.PublicView.class)
, @JsonView(Profile.FriendsView.class)
and @JsonView(Profile.FamilyView.class)
Address.java
package com.concretepage.pojo; import com.concretepage.Profile; import com.fasterxml.jackson.annotation.JsonView; public class Address { @JsonView(Profile.FamilyView.class) private String houseNo; @JsonView(Profile.FriendsView.class) private String city; @JsonView(Profile.PublicView.class) private String country; public Address(String houseNo, String city, String country) { this.houseNo = houseNo; this.city = city; this.country = country; } public String getHouseNo() { return houseNo; } public void setHouseNo(String houseNo) { this.houseNo = houseNo; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } }
package com.concretepage.pojo; import com.concretepage.Profile; import com.fasterxml.jackson.annotation.JsonView; public class College { @JsonView(Profile.PublicView.class) private String colName; @JsonView(Profile.FriendsView.class) private String colLocation; public College(String colName, String colLocation) { this.colName = colName; this.colLocation = colLocation; } public String getColName() { return colName; } public void setColName(String colName) { this.colName = colName; } public String getColLocation() { return colLocation; } public void setColLocation(String colLocation) { this.colLocation = colLocation; } }
package com.concretepage.pojo; import com.concretepage.Profile; import com.fasterxml.jackson.annotation.JsonView; public class User { @JsonView(Profile.PublicView.class) private String userId; private String password; private int age; @JsonView(Profile.FamilyView.class) private long mobnum; @JsonView(Profile.FriendsView.class) private String mailId; @JsonView(Profile.PublicView.class) private String name; @JsonView(Profile.PublicView.class) private College college; @JsonView(Profile.PublicView.class) private Address address; public User(String userId, String password, int age, long mobnum, String mailId, String name, College college, Address address) { this.userId = userId; this.password = password; this.age = age; this.mobnum = mobnum; this.mailId = mailId; this.name = name; this.college = college; this.address = address; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public long getMobnum() { return mobnum; } public void setMobnum(long mobnum) { this.mobnum = mobnum; } public String getMailId() { return mailId; } public void setMailId(String mailId) { this.mailId = mailId; } public String getName() { return name; } public void setName(String name) { this.name = name; } public College getCollege() { return college; } public void setCollege(College college) { this.college = college; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } }
package com.concretepage.pojo; public class Name { private String firstName; private String middleName; private String lastName; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getMiddleName() { return middleName; } public void setMiddleName(String middleName) { this.middleName = middleName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
Create Spring MVC Controller with @JsonView Annotation
Spring 4.1 onwards it directly supports Jackson@JsonView
annotation. In our controller the methods annotated with @RequestMapping
can be directly annotated with @JsonView
to filter JSON view in serialized response body.
1. In our example the controller method annotated with
@JsonView(Profile.PublicView.class)
will produce JSON response only with public view properties.
2. The controller method annotated with
@JsonView(Profile.FriendsView.class)
will produce JSON response with public and friends view properties.
3. The controller method annotated with
@JsonView(Profile.FamilyView.class)
will produce JSON response with public, friends and family view properties.
4. The controller method
getCompleteProfileById()
has not been annotated with any view. It will produce JSON with each and every property as usual.
UserController.java
package com.concretepage; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.concretepage.pojo.Name; import com.concretepage.pojo.User; import com.fasterxml.jackson.annotation.JsonView; @RestController @RequestMapping("/app") public class UserController { @Autowired private UserService userService; @JsonView(Profile.PublicView.class) @RequestMapping(value= "/publicprofile", produces = MediaType.APPLICATION_JSON_VALUE) public List<User> getAllPublicProfile() { List<User> users = userService.getAllUsers(); return users; } @JsonView(Profile.FriendsView.class) @RequestMapping(value= "/friendsprofile", produces = MediaType.APPLICATION_JSON_VALUE) public List<User> getAllFriendsProfile() { List<User> users = userService.getAllUsers(); return users; } @JsonView(Profile.FamilyView.class) @RequestMapping(value= "/familyprofile", produces = MediaType.APPLICATION_JSON_VALUE) public List<User> getAllFamilyProfile() { List<User> users = userService.getAllUsers(); return users; } @RequestMapping(value= "/completeprofile/{userId}", produces = MediaType.APPLICATION_JSON_VALUE) public User getCompleteProfileById(@PathVariable(value = "userId") String userId) { User user = userService.getUserById(userId); return user; } @RequestMapping(value="/save", method = RequestMethod.POST) public ResponseEntity<String> save(@RequestBody Name name) { StringBuffer output = new StringBuffer(); if (name.getFirstName() != null) { output.append(" ").append(name.getFirstName()); } if (name.getMiddleName() != null) { output.append(" ").append(name.getMiddleName()); } if (name.getLastName() != null) { output.append(" ").append(name.getLastName()); } return new ResponseEntity<String>(output.toString(), HttpStatus.CREATED); } }
package com.concretepage; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; import org.springframework.stereotype.Service; import com.concretepage.pojo.Address; import com.concretepage.pojo.College; import com.concretepage.pojo.User; @Service public class UserService { public User getUserById(String userId) { Predicate<User> userPredicate = u-> u.getUserId().equals(userId); User obj = list.stream().filter(userPredicate).findFirst().get(); return obj; } public List<User> getAllUsers() { return list; } private List<User> list = new ArrayList<>(); { Address address = new Address("A-32", "Varanasi", "India"); College college = new College("UP College", "Varanasi"); User user = new User("mohan", "m123", 20, 988745 ,"mohan@gmail.com", "Mohan", college, address); list.add(user); address = new Address("C-50", "Allahabad", "India"); college = new College("Allahabad University", "Allahabad"); user = new User("krishna", "k123", 25, 988345, "krishna@gmail.com", "Krishna", college, address); list.add(user); address = new Address("D-40", "Delhi", "India"); college = new College("JNU", "Delhi"); user = new User("mahesh", "mh123", 30, 988765, "mahesh@gmail.com", "Mahesh", college, address); list.add(user); } }
Create Java Configuration and Application Initializer
Find the java configuration used in our example.AppConfig.java
package com.concretepage.config; import java.util.List; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration @ComponentScan("com.concretepage") @EnableWebMvc public class AppConfig extends WebMvcConfigurerAdapter { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder(); builder.indentOutput(true); converters.add(new MappingJackson2HttpMessageConverter(builder.build())); } }
WebAppInitializer.java
package com.concretepage.config; import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class[] { AppConfig.class }; } @Override protected Class<?>[] getServletConfigClasses() { return null; } @Override protected String[] getServletMappings() { return new String[]{"/"}; } }
Run Application
To run the application, find the below steps.1. Download source code and navigate to root directory of the project.
2. Run command gradle clean build using command prompt.
3. Deploy the WAR file in tomcat.
4. To test the
@JsonView(Profile.PublicView.class)
, run the URL as given below.
http://localhost:8080/spring-rest-1/app/publicprofile
We will get JSON output as follows.
[ { "userId" : "mohan", "name" : "Mohan", "college" : { "colName" : "UP College" }, "address" : { "country" : "India" } }, { "userId" : "krishna", "name" : "Krishna", "college" : { "colName" : "Allahabad University" }, "address" : { "country" : "India" } }, { "userId" : "mahesh", "name" : "Mahesh", "college" : { "colName" : "JNU" }, "address" : { "country" : "India" } } ]
@JsonView(Profile.FriendsView.class)
, run the URL as given below.
http://localhost:8080/spring-rest-1/app/friendsprofile
We will get JSON output as follows.
[ { "userId" : "mohan", "mailId" : "mohan@gmail.com", "name" : "Mohan", "college" : { "colName" : "UP College", "colLocation" : "Varanasi" }, "address" : { "city" : "Varanasi", "country" : "India" } }, { "userId" : "krishna", "mailId" : "krishna@gmail.com", "name" : "Krishna", "college" : { "colName" : "Allahabad University", "colLocation" : "Allahabad" }, "address" : { "city" : "Allahabad", "country" : "India" } }, { "userId" : "mahesh", "mailId" : "mahesh@gmail.com", "name" : "Mahesh", "college" : { "colName" : "JNU", "colLocation" : "Delhi" }, "address" : { "city" : "Delhi", "country" : "India" } } ]
@JsonView(Profile.FamilyView.class)
, run the URL as given below.
http://localhost:8080/spring-rest-1/app/familyprofile
We will get JSON output as follows.
[ { "userId" : "mohan", "mobnum" : 988745, "mailId" : "mohan@gmail.com", "name" : "Mohan", "college" : { "colName" : "UP College", "colLocation" : "Varanasi" }, "address" : { "houseNo" : "A-32", "city" : "Varanasi", "country" : "India" } }, { "userId" : "krishna", "mobnum" : 988345, "mailId" : "krishna@gmail.com", "name" : "Krishna", "college" : { "colName" : "Allahabad University", "colLocation" : "Allahabad" }, "address" : { "houseNo" : "C-50", "city" : "Allahabad", "country" : "India" } }, { "userId" : "mahesh", "mobnum" : 988765, "mailId" : "mahesh@gmail.com", "name" : "Mahesh", "college" : { "colName" : "JNU", "colLocation" : "Delhi" }, "address" : { "houseNo" : "D-40", "city" : "Delhi", "country" : "India" } } ]
getCompleteProfileById()
method, run the URL as given below.
http://localhost:8080/spring-rest-1/app/completeprofile/krishna
We will get JSON output as follows.
{ "userId" : "krishna", "password" : "k123", "age" : 25, "mobnum" : 988345, "mailId" : "krishna@gmail.com", "name" : "Krishna", "college" : { "colName" : "Allahabad University", "colLocation" : "Allahabad" }, "address" : { "houseNo" : "C-50", "city" : "Allahabad", "country" : "India" } }
Spring REST Client with @JsonView using MappingJacksonValue
The Jackson@JsonView
annotation can also be used with RestTemplate
in spring REST client. To achieve it spring provides MappingJacksonValue
. It wraps the given POJO to be serialized. For the example we are creating user name example. A user name can have first, middle and last name. We are creating name views such as FirstName
and FirstLastName
. Find the view defined for user name.
NameView.java
package com.concretepage; public class NameView { public interface FirstName {} public interface FirstLastName extends FirstName {} }
Name.java
package com.concretepage.pojo; import com.concretepage.NameView; import com.fasterxml.jackson.annotation.JsonView; public class Name { @JsonView(NameView.FirstName.class) private String firstName; private String middleName; @JsonView(NameView.FirstLastName.class) private String lastName; public Name(String firstName, String middleName, String lastName) { this.firstName = firstName; this.middleName = middleName; this.lastName = lastName; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getMiddleName() { return middleName; } public void setMiddleName(String middleName) { this.middleName = middleName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } }
MappingJacksonValue
we wrap our POJO as follows.
Name name = new Name("Arvind", "Kumar", "Rai"); MappingJacksonValue jacksonValue = new MappingJacksonValue(name);
jacksonValue.setSerializationView(NameView.FirstLastName.class);
UserController
class, we have exposed a method as given below.
@RequestMapping(value="/save", method = RequestMethod.POST) public ResponseEntity<String> save(@RequestBody Name name) { StringBuffer output = new StringBuffer(); if (name.getFirstName() != null) { output.append(" ").append(name.getFirstName()); } if (name.getMiddleName() != null) { output.append(" ").append(name.getMiddleName()); } if (name.getLastName() != null) { output.append(" ").append(name.getLastName()); } return new ResponseEntity<String>(output.toString(), HttpStatus.CREATED); }
postForObject()
.
PostForObjectDemo.java
package com.concretepage; import java.nio.charset.Charset; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.converter.json.MappingJacksonValue; import org.springframework.web.client.RestTemplate; import com.concretepage.pojo.Name; public class PostForObjectDemo { public static void main(String args[]) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(new MediaType("application", "json", Charset.forName("UTF-8"))); Name name = new Name("Arvind", "Kumar", "Rai"); MappingJacksonValue jacksonValue = new MappingJacksonValue(name); jacksonValue.setSerializationView(NameView.FirstLastName.class); HttpEntity<MappingJacksonValue> entity = new HttpEntity<MappingJacksonValue>(jacksonValue, headers); String url = "http://localhost:8080/spring-rest-1/app/save"; RestTemplate restTemplate = new RestTemplate(); String output = restTemplate.postForObject(url, entity, String.class); System.out.println("Name:"+ output); } }
1. If serialization view is
NameView.FirstName.class
, the output will be
Name:" Arvind"
NameView.FirstLastName.class
, the output will be
Name:" Arvind Rai"
Name:" Arvind Kumar Rai"
Now I am done. Happy spring learning!