Developing Jersey JAX-RS RESTful Web Services

1 Comment
jersey jax-rs

For some days I’ve been tinkering with the Jersey JAX-RS framework in order to develop some RESTful Java web services, so here’s a tutorial (and a memoir for me) on how to use this beautiful framework.

1- Build the project

I will be using Eclipse Luna for this tutorial so let’s start by creating a new Maven project.

It will be a simple project without any predefined archetype.

Provide the group id, artifact id, a version and set packaging to war.

The new project will be created with the following structure:

Now before adding the dependencies, let’s configure the new project. By default the project’s Web Module is set to 2.5, we will change that to 3.1 so we can deploy the web services on a Servlet 3.1 container such as Tomcat 8. To do so, right click on the project root and choose Properties, then select Project Facets and choose version 3.1 for Dynamic Web Module. (And yes you need to set Java to 1.7 as well)

Maven’s Java compiler level must be set to 1.7, so add the following in pom.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<build>
	<pluginManagement>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.3</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	</pluginManagement>
</build>

2- Dependencies!

I love Maven, we all do, so let’s add some dependencies to our project. We will start by adding the Jersey jars:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- Jersey Core -->
<dependency>
	<groupId>org.glassfish.jersey.core</groupId>
	<artifactId>jersey-server</artifactId>
	<version>2.22.2</version>
</dependency>
<!-- Jersey provides two Servlet modules. The first module is the 
Jersey core Servlet module that provides the core Servlet 
integration support and is required in any Servlet 2.5 or higher container: -->
<dependency>
	<groupId>org.glassfish.jersey.containers</groupId>
	<artifactId>jersey-container-servlet-core</artifactId>
	<version>2.22.2</version>
</dependency>
<!-- To support additional Servlet 3.x deployment modes and asynchronous JAX-RS 
resource programming model, an additional Jersey module is required: -->
<dependency>
	<groupId>org.glassfish.jersey.containers</groupId>
	<artifactId>jersey-container-servlet</artifactId>
	<version>2.22.2</version>
</dependency>

We need a CORS Servlet filter, so we will use this simple filter created by Vladimir Dzhuvinov:

1
2
3
4
5
6
<!-- CORS -->
<dependency>
	<groupId>com.thetransactioncompany</groupId>
	<artifactId>cors-filter</artifactId>
	<version>2.5</version>
</dependency>

Last but not least, we need a JSON library to serialize our responses, GENSON is one the best out there, as it is stated on its Github page – “Just drop the jar in your classpath to enable Json support in a JAX-RS Application” – and that’s what we’re going to do:

1
2
3
4
5
6
<!-- GENSON for JSON -->
<dependency>
	<groupId>com.owlike</groupId>
	<artifactId>genson</artifactId>
	<version>1.3</version>
</dependency>

And that will be all for now.

3- Deployment and the first Web Service

Deployment configuration can take different forms, we can use the Deployment Descriptor a.k.a web.xml, or we can use the @ApplicationPath annotation for more simplicity.

So we will create a class with an @ApplicationPath that extends org.glassfish.jersey.server.ResourceConfig. The value provided to the annotation determines the base URI for the application, so after you install your WAR file on Tomcat, you can access your Web Services using:

http://localhost:8080/app/<-annotation-value->

The ResourceConfig object will contain all the configurations for this JAX-RS application, we can register Filters, Interceptors and Resources.

In the constructor of our application class we need to inform Jersey in which packages it can locate the web services classes:

1
2
3
4
5
6
7
8
9
10
11
12
package com.alibassam.jersey_server;
 
import javax.ws.rs.ApplicationPath;
 
import org.glassfish.jersey.server.ResourceConfig;
 
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
	public JerseyApplication() {
		packages("com.alibassam.jersey_server.services");
	}
}

Screenshot from 2016-02-20 22:27:49

And now we can start creating our web services. Each class will represent a different URL, and each method will represent a different endpoint of that URL, as a start we will create a class named WelcomeService with a @Path(“/welcome”) annotation, this means that in order to access the methods of this class, we need to call the following URL:

http://localhost:8080/app/services/welcome

Inside this class we will create a method with a @GET annotation, and a @Path(“hello”) annotation which will define the complete URL to access this service:

http://localhost:8080/app/services/welcome/hello

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.alibassam.jersey_server.services;
 
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;
 
@Path("/welcome")
public class WelcomeService {
 
	@GET
	@Path("hello")
	public Response helloWorld() {
		String welcomeMessage = "Hello World!";
		return Response.ok(welcomeMessage).build();
	}
}

Now deploy your application on Tomcat, browse to that endpoint and check the result!

4- Some tiny basic security

For security well there are many things to do, it can be very complex and it can be simple, but as a start let’s implement some basic security features that any web services application should have.

We previously added the CORS Filter dependency but we haven’t used it yet, now this filter will go into action. The CORS filter will basically put restrictions on the requests coming from a different origin than the origin of your web services (different IP/Port), these are restrictions on HTTP Methods (GET, POST, PUT, etc…), restrictions on HTTP Request Headers (Content-Type, WWW-Athenticate, etc…) and other things. This filter is useful to set the rules of access for your web services.

Now all we need to do is to add a filter and a filter-mapping inside our Deployment Descriptor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://xmlns.jcp.org/xml/ns/javaee"
	xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
	version="3.1">
	<display-name>jersey-server</display-name>
	<!-- CORS -->
	<filter>
		<filter-name>CORS</filter-name>
		<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
		<init-param>
			<param-name>cors.allowOrigin</param-name>
			<param-value>*</param-value>
		</init-param>
		<init-param>
			<param-name>cors.supportedMethods</param-name>
			<param-value>GET, POST, HEAD, PUT, DELETE, OPTIONS</param-value>
		</init-param>
		<init-param>
			<param-name>cors.supportedHeaders</param-name>
			<param-value>Accept, Origin, X-Requested-With, Content-Type,
                Last-Modified, WWW-Authenticate</param-value>
		</init-param>
		<init-param>
			<param-name>cors.exposedHeaders</param-name>
			<param-value>Set-Cookie</param-value>
		</init-param>
		<init-param>
			<param-name>cors.supportsCredentials</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>CORS</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

I suggest you check this configuration page for more detailed features of this filter, lots of cool stuff!

Now let’s create a custom Request Filter, we can put filters on requests to our web services and responses generated from our web services, for what purpose? Well we have to use our imagination, you can basically check the request and do any logic that you find useful, the whole purpose is to either let the request pass or refuse it.

We will create a Class called AuthenticationFilter which will implement the javax.ws.rs.container.ContainerRequestFilter interface that provides the filter method where we can intercept the incoming request.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.alibassam.jersey_server.filters;
 
import java.io.IOException;
 
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
 
public class AuthenticationFilter implements ContainerRequestFilter {
 
	@Override
	public void filter(ContainerRequestContext requestContext) throws IOException {
		String authHeader = requestContext.getHeaderString(HttpHeaders.WWW_AUTHENTICATE);
		if(authHeader == null || "".equals(authHeader)) {
			String returnMessage = "You are not allowed to acess these webservices";
			throw new WebApplicationException(Response.status(Status.FORBIDDEN).entity(returnMessage).build());
		}
	}
 
}

In this example, the Request Filter will check for a WWW-Authenticate header in the request, in case it is found the request will proceed, otherwise it will be rejected. (Or you can decode it, retrieve a token, check if this token is valid, etc…)

But wait, that’s not everything, we need to register this filter in our application class, you can actually use a @Provider annotation on the filter class but I prefer to keep all registrations in one place. So let’s register our filter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.alibassam.jersey_server;
 
import javax.ws.rs.ApplicationPath;
 
import org.glassfish.jersey.server.ResourceConfig;
 
import com.alibassam.jersey_server.filters.AuthenticationFilter;
 
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
	public JerseyApplication() {
		packages("com.alibassam.jersey_server.services");
 
		register(AuthenticationFilter.class);
	}
}

Now let’s check if we are still welcomed or not! (Request the Hello World service without an authentication header)

5- Exception Handling

As in any Java application, there is a possibility that many Exceptions will be thrown, in a JAX-RS application there is a cool way to handle these Exceptions, and to map each one of them to specific Responses that will be returned to the client.

We will create a new Class called ExceptionHandler that implements the avax.ws.rs.ext.ExceptionMapper interface and we can set what type of Exception is supported in this handler, so we will simply use the main java.lang.Exception Class to handle all types of Exceptions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.alibassam.jersey_server.utils;
 
import java.io.IOException;
 
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.ExceptionMapper;
 
public class ExceptionHandler implements ExceptionMapper<Exception> {
 
	@Override
	public Response toResponse(Exception exception) {
		if(exception instanceof IOException) {
			return Response.status(503).build();
		}
		else {
			return Response.status(500).build();
		}
	}
 
}

You can use more than a single Exception Handler for different kinds of Exceptions, I prefer to handle them all in one class, One Class To Rule Them All, One Class To Find Them, One Class To Bring Them All, And In The Darkness Bind Them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.alibassam.jersey_server;
 
import javax.ws.rs.ApplicationPath;
 
import org.glassfish.jersey.server.ResourceConfig;
 
import com.alibassam.jersey_server.filters.AuthenticationFilter;
import com.alibassam.jersey_server.utils.ExceptionHandler;
 
@ApplicationPath("services")
public class JerseyApplication extends ResourceConfig {
	public JerseyApplication() {
		packages("com.alibassam.jersey_server.services");
 
		register(AuthenticationFilter.class);
		register(ExceptionHandler.class);
	}
}

6- Other useful things

What you have just seen is pretty basic, but it is enough to kick-start your Java Web-Services. Here are other things that you may find useful:

You can enable compression of Responses by registering filters and encoders, Jersey provides us with these cool features:

1
2
3
register(EncodingFilter.class);
register(GZipEncoder.class);
register(DeflateEncoder.class);

You can also integrate the Jersey Server with other frameworks such as Spring and JSF Managed Beans, Jersey also provides more complex security implementations. All of this can be found in the wonderful easy to read Jersey documentation.

You can find this Jersey Server example on Github.

Categories: Java, Web Services Tags: Tags: , , ,

One Reply to “Developing Jersey JAX-RS RESTful Web Services”

Leave a Reply

%d bloggers like this: