Spring MVC 4 REST + Jackson @JsonView Annotation Integration Example

By Arvind Rai, 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.

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.
Spring MVC 4 REST + Jackson @JsonView Annotation Integration Example

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 {}
} 
Look at the class. We are creating a view filter mechanism for the user profile. We are creating three profile views and those are public view, friends view and family view. Friends view is inheriting public view and family view is inheriting friends view.

Create POJO Using Jackson @JsonView Annotation

Jackson provides the annotation com.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;
	}
} 
College.java
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;
	}
} 
User.java
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;
	}
} 
Name.java
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);
	} 
} 
UserService.java
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()));
    }	
} 
Find the web application initializer.
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"
  }
} ] 
5. To test the @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"
  }
} ] 
6. To test the @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"
  }
} ] 
7. To test the 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 {}	
} 
Find the POJO being used in our REST client example.
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;
	}
} 
Now using MappingJacksonValue we wrap our POJO as follows.
Name name = new Name("Arvind", "Kumar", "Rai");
MappingJacksonValue jacksonValue = new MappingJacksonValue(name); 
To filter the view, set the serialization view as follows.
jacksonValue.setSerializationView(NameView.FirstLastName.class);
 
In REST web service 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);
}  
Now find the REST client code with 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);
    }
} 
The output will be as follows.
1. If serialization view is NameView.FirstName.class, the output will be
Name:" Arvind"
 
2. If serialization view is NameView.FirstLastName.class, the output will be
Name:" Arvind Rai"
 
3. If no view is assigned, the output will be as usual.
Name:" Arvind Kumar Rai"
 

Now I am done. Happy spring learning!

Reference

Latest Jackson integration improvements in Spring

Download Complete Source Code

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us