Consume, produce and ignore JSON properties with Jersey2

In this tutorial we discuss how you can automatically consume and produce JSON using Jersey2 Rest web services. Furthermore we demonstrate the usage of annotations to exclude properties from being serialized or deserialized using FasterXML/Jackson and the @JsonIgnore as well as @JsonProperty annotation. You can download the example code at Github.

1. Prerequisites

  1. Install Apache Tomcat (we use version 8.5). If not already installed, please have a look at these 2 tutorials:
  2. Install Apache Maven to build the project
  3. You can just run a “clean install” on the Maven project and deploy the created WAR file to Tomcat directly. Although we recommend to work with an IDE like EclipseEE or IntelliJ to adapt or debug the project
  4. Some tool to test the REST Api (we use Postman)
  5. If you import the Maven project to EclipseEE, activate and adapt the Project Facets to use the Dynamic Web Project 3.1, Java 1.8 and JAX-RS 2.0

2. Code step-by-step

The web.xml and pom.xml files are available in the Git repository. The only remark concerning the XML files will be the required dependencies.

2.1 Maven dependencies

		<dependency>
			<groupId>org.glassfish.jersey.containers</groupId>
			<artifactId>jersey-container-servlet</artifactId>
			<version>${jersey2.version}</version>
		</dependency>
		<dependency>
			<groupId>org.glassfish.jersey.containers</groupId>
			<artifactId>jersey-container-servlet-core</artifactId>
			<version>${jersey2.version}</version>
		</dependency>
		<dependency>
			<groupId>org.glassfish.jersey.media</groupId>
			<artifactId>jersey-media-json-jackson</artifactId>
			<version>${jersey2.version}</version>
		</dependency>

In order to consume and produce JSON automatically, the jersey-media-json-jackson is required. It will take care of the serialization and deserilization of JSON into POJOs and the other way round.

2.2 REST web service

The following code is our REST endpoint providing three methods which all use a different User POJO with different annotations.

@Path("/user")
public class UserRestService extends ResourceConfig { 
	
	final static Logger logger = Logger.getLogger( UserRestService.class );
	
	@POST
	@Path("/userNoAnnotation")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response userNoAnnotation( UserNoAnnotation user ) {
		logger.info( user );
		
		return Response.ok( user ).build();
	}	
	
	@POST
	@Path("/userHidePassword")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response userHidePassword( UserHidePassword user ) {
		logger.info( user );
		
		return Response.ok( user ).build();
	}
	
	@POST
	@Path("/userIgnorePassword")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response userIgnorePassword( UserIgnorePassword user ) {
		logger.info( user );
		
		return Response.ok( user ).build();
	}
	
}

As you can see we want to test three different user implementations. All user implementations require the same data: a name and a password. The difference between the users are the annotations. We explain the different user implementations later. First lets have a look at the JSON data we want to consume.

2.3 JSON data

{
	"name" : "Mark Twain",
	"password" : "secret"
}

The data we send to the REST service is straight forward. We want to register a user with a password. Consequently, when sending the user in the response, returning the password (hashed or plain) must be avoided. Let us have a look on the three user implementations, their annotations and what the logging output and the returned JSON data looks like.

2.4 UserNoAnnotation

public class UserNoAnnotation {
	private String name = null;
	private String password = null;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String toString() {
		return "UserNoAnnotation [name=" + name + ", password=" + password + "]";
	}
}

Using Postman to send a POST request using the JSON data from above, results in the following output:

Postman_UserNoAnnotation_Screen

As we can see the response returns the exact user we send. The password is visible and send back to the client. You want to avoid that all the time. We can use the @JsonIgnore property to indicate Jackson to exclude that property from serialization and deserialization.

2.5 UserIgnorePassword

public class UserIgnorePassword {
	private String name = null;
	
	@JsonIgnore
	private String password = null;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String toString() {
		return "UserIgnorePassword [name=" + name + ", password=" + password + "]";
	}
	
}

Now let us check what happens if we add the @JsonIgnore annotation to the password attribute.

Postman_UserIgnorePassword_Screen

The response seems to be correct. There is no password in the response. When inspecting the logger output, another problem appears:

INFO [UserRestService.java:43:userIgnorePassword()] - UserIgnorePassword [name=Mark Twain, password=null]

When printing the UserIgnorePassword object we ascertain that the password is null. We excluded the password from serialization and deserialization completely. Consequently, hashing and storing the password in a database or further process other data is impossible. Continuing to the third user implementation, we demonstrate how you set the right annotations using @JsonIgnore and @JsonProperty.

2.6 UserHidePassword

public class UserHidePassword {
	
	private String name = null;
	
	@JsonIgnore
	private String password = null;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@JsonIgnore
	public String getPassword() {
		return password;
	}

	@JsonProperty
	public void setPassword(String password) {
		this.password = password;
	}

	@Override
	public String toString() {
		return "UserHidePassword [name=" + name + ", password=" + password + "]";
	}
	
}

In addition to the @JsonIgnore annotation we added another @JsonIgnore to the password getter. During the POJO to JSON conversion, the getPassword() method is ignored. Therefore, the JSON response will not contain any password property. Let us have a look at the Postman output.

Postman_UserHidePassword_Screen

As expected the JSON response does not contain any password property. After inspecting the logger output, we can conclude that the password arrived in the user POJO correctly and is ready to be processed.

INFO [UserRestService.java:33:userHidePassword()] - UserHidePassword [name=Mark Twain, password=secret]

You can use the same approach to ignore setting attributes in your POJO you want to generate manually. E.g. create an unique id or a date of the user’s first registration. That is the responsibility of the server and not the REST client.

3. Conclusion

The automated serialization and deserilization of JSON into POJOs and POJOs into JSON simplifies the development of JSON based REST applications alot. You do not need extra code or libraries. It is possible to deserialize more complex data structures (e.g. user POJO with embedded address POJO, Arrays, Lists etc). The usage of the provided annotations the request and response enables you to filter and manipulate your data to your requirements accordingly.

There is a follow up tutorial to the @JsonIgnoreProperties annotation using the same Git project. Have a look here.

If you have errors or problems, feel free to comment and ask.

Facebooktwitterredditpinterestlinkedinmail

Related posts

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.