REST Assured Tutorial 36 – @JsonInclude Annotation – Ignore Default Values In Payload

As a part of End to End REST Assured Tutorial, in this post, We will learn about an important annotation @JsonInclude of Jackson library which helps in eliminating default, null, empty, etc values. For this post, we will focus on default values.

Suppose we have an Employee POJO as below:-

package JacksonTutorials;

public class Employee {

	// private variables or data members of pojo class
	private String firstName;
	private String lastName;
	private String gender;
	private int age;
	private double salary;
	private boolean married;
	
	// Getter and setter methods
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public boolean getMarried() {
		return married;
	}
	public void setMarried(boolean married) {
		this.married = married;
	} 	
}

It may not be mandatory to pass values to all fields in a payload. For example, a “gender” field may be optional and you just need not set the value to it in the payload. You need to pass payload as below:-

{
  "firstName" : "Amod",
  "lastName" : "Mahajan",
  "age" : 29,
  "salary" : 3434343.0,
  "married" : true
}

Let’s not set a value to “gender” field and serialize Java Object to JSON object as below:-

package JacksonTutorials;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;


public class AnnotationJsonIncludeExample {

	public static void main(String[] args) throws JsonProcessingException {

		// Just create an object of Pojo class
		Employee employee = new Employee();
		// Set value as you wish
		employee.setFirstName("Amod");
		employee.setLastName("Mahajan");
		employee.setAge(29);
		employee.setSalary(3434343);
		employee.setMarried(true);
		
		// Converting a Java class object to a JSON payload as string
		ObjectMapper objectMapper = new ObjectMapper();
		String employeeJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(employee);
		System.out.println(employeeJson);
	}
}

Output

{
  "firstName" : "Amod",
  "lastName" : "Mahajan",
  "gender" : null,
  "age" : 29,
  "salary" : 3434343.0,
  "married" : true
}

Did we want payload as above? No. We do not want a field “gender” to be included. We know those class variables are assigned a default value. When we do not explicitly set values to class variables then while serializing it used default values. Since ‘gender‘ is a String field whose default value is ‘null‘.

Let’s not set a value to a field ‘age’ now.

package JacksonTutorials;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;


public class AnnotationJsonIncludeExample {

	public static void main(String[] args) throws JsonProcessingException {

		// Just create an object of Pojo class
		Employee employee = new Employee();
		// Set value as you wish
		employee.setFirstName("Amod");
		employee.setLastName("Mahajan");
		employee.setSalary(3434343);
		employee.setMarried(true);
		
		// Converting a Java class object to a JSON payload as string
		ObjectMapper objectMapper = new ObjectMapper();
		String employeeJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(employee);
		System.out.println(employeeJson);
	}
}

Output

{
  "firstName" : "Amod",
  "lastName" : "Mahajan",
  "gender" : null,
  "age" : 0,
  "salary" : 3434343.0,
  "married" : true
}

You can see how default value for an integer field ‘age‘ was taken as zero when we did not set any value to it.

We do not want a field with a default value to come to the target payload. For this, we can use an annotation @JsonInclude in POJO class at the class level and individual property level provided by Jackson Java API.

package JacksonTutorials;

import com.fasterxml.jackson.annotation.JsonInclude;

@JsonInclude(JsonInclude.Include.NON_DEFAULT)
public class Employee {

	// private variables or data members of pojo class
	private String firstName;
	private String lastName;
	private String gender;
	private int age;
	private double salary;
	private boolean married;
	
	// Getter and setter methods
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public boolean getMarried() {
		return married;
	}
	public void setMarried(boolean married) {
		this.married = married;
	} 	
}

Now if we rerun class “AnnotationJsonIncludeExample” then we will get the output as below which we want.

{
  "firstName" : "Amod",
  "lastName" : "Mahajan",
  "salary" : 3434343.0,
  "married" : true
}

@JsonInclude annotation is used to indicate when the value of the annotated property (when used for a field, method, or constructor parameter), or all properties of the annotated class, is to be serialized. Without the annotation, property values are always included, but by using this annotation one can specify simple exclusion rules to reduce the number of properties to write out.

We have multiple options in Enum Include shown below:-

ALWAYSValue that indicates that property is to be always included, independent of value of the property.
CUSTOMValue that indicates that separate `filter` Object (specified by JsonInclude.valueFilter() for value itself, and/or JsonInclude.contentFilter() for contents of structured types) is to be used for determining inclusion criteria.
NON_ABSENTValue that indicates that properties are included unless their value is: null “absent” value of a referential type (like Java 8 `Optional`, or { java.utl.concurrent.atomic.AtomicReference}); that is, something that would not deference to a non-null value.
NON_DEFAULTMeaning of this setting depends on context: whether annotation is specified for POJO type (class), or not.
NON_EMPTYValue that indicates that only properties with null value, or what is considered empty, are not to be included.
NON_NULLValue that indicates that only properties with non-null values are to be included.
USE_DEFAULTSPseudo-value used to indicate that the higher-level defaults make sense, to avoid overriding inclusion value.

In the above example, we added @JsonIgnore at a class level which will be applicable for all members of a class. If we want for specific field of a class then we can use at property level. An example is as below:-

package JacksonTutorials;

import com.fasterxml.jackson.annotation.JsonInclude;


public class Employee {

	// private variables or data members of pojo class
	@JsonInclude(JsonInclude.Include.NON_DEFAULT)
	private String firstName;
	@JsonInclude(JsonInclude.Include.NON_DEFAULT)
	private String lastName;
	@JsonInclude(JsonInclude.Include.NON_DEFAULT)
	private String gender;
	private int age;
	private double salary;
	private boolean married;
	
	// Getter and setter methods
	public String getFirstName() {
		return firstName;
	}
	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}
	public String getLastName() {
		return lastName;
	}
	public void setLastName(String lastName) {
		this.lastName = lastName;
	}
	public String getGender() {
		return gender;
	}
	public void setGender(String gender) {
		this.gender = gender;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public boolean getMarried() {
		return married;
	}
	public void setMarried(boolean married) {
		this.married = married;
	} 	
}

If all fields of class have the same annotation then it is better to use at the class level. But if you want to use different inclusions like NON_NULL, NON_DEFAULT, NON_EMPTY, etc on different properties of a class then use at property level.

There is a frequently asked interview question on this. If we are ignoring default values of fields and a user tries to pass default values explicitly or based on some condition, will that be ignored by the above annotation with include value? The answer is Yes. It will be ignored.

We will see more examples in upcoming posts.

You can download/clone the above sample project from here.

If you have any doubt, feel free to comment below.
If you like my posts, please like, comment, share and subscribe.
#ThanksForReading
#HappyLearning

Find all Selenium related posts here, all API manual and automation related posts here, and find frequently asked Java Programs here.

Many other topics you can navigate through the menu.

1 thought on “REST Assured Tutorial 36 – @JsonInclude Annotation – Ignore Default Values In Payload

  1. In this post you have mentioned a sentence “In the above example, we added @JsonIgnore at a class level” but the example is of @JsonInclude.

Leave a Reply

Your email address will not be published. Required fields are marked *