rest

JAX-RS Tutorial with Jersey for RESTful Web Services

1. Introduction

In this post, we feature a comprehensive tutorial on JAX-RS with Jersey for RESTful Web Services. Java API for RESTful Web Services (JAX-RS) is a Java programming language API specification that provides support in creating web services according to the Representational State Transfer (REST) architectural pattern. Jersey is Sun’s implementation for JAX-RS. Jersey not only implements the annotations defined in JAX-RS, but also provides its own APIs to simplify the web service creation.

JAX-RS common annotations are:

  • @Produces – specify the type of output this web service will produce
  • @Consumes – specify the MIME media types this web service can consume
  • @Path – specify the URL path on which this method will be invoked
  • @PathParam – bind REST-style URL parameters to method arguments
  • @QueryParam – access the request parameters in query string
  • @POST – create a resource
  • @GET – retrieve a resource
  • @PUT – update the resource
  • @DELETE – delete the resource

Jersey’s common APIs are:

In this tutorial, I will demonstrate how to build RESTful web services utilizing JAX-RS annotations along with Jersey library in a Spring Boot Maven project. These web services include:

  1. Read service – returns a given user with GET action.
  2. Search service – displays matching users with GET action.
  3. Create service – creates a new user with POST action.
  4. Update service – updates the user with PUT action.
  5. Delete service – deletes the user with DELETE action.

2. Technologies Used

The example code in this article was built and run using:

  • Java 1.8.101 (1.8.x will do fine)
  • Maven 3.3.9 (3.3.x will do fine)
  • Spring boot 1.5.14 (Higher version will do fine)
  • Jersey 2.4.x (Higher version will do fine)
  • Eclipse Oxygen (Any Java IDE would work)
  • H2 Database

3. Spring Boot Web Application

There are many ways to create a Spring boot Jersey application. The easiest way for me is via the Spring starter tool with the steps below:

  1. Go to https://start.spring.io/.
  2. Select Maven Project with Java and Spring Boot version 1.5.14 and type in Jersey (JAX-RS), JPA, and H2 in the “search for dependencies” bar.
  3. Enter the group name as jcg.zheng.demo and artifact as spring-boot-jersey-demo.
  4. Click the Generate Project button.

A maven project will be generated and downloaded to your workstation. Import it into your Eclipse workspace.

3.1 Dependency

Maven pom.xml manages the project libraries. The generated pom.xml contains everything we need for this example.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>jcg.zheng.demo</groupId>
	<artifactId>spring-boot-jersey-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>spring-boot-jersey-demo</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.14.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jersey</artifactId>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

3.2 Spring Boot Application

In this step, I will update the generated SpringBootJerseyDemoApplication to include Jersey RESTful resources.

First, I will create UnhandledExceptionMapper which implements org.glassfish.jersey.spi.ExtendedExceptionMapper.

UnhandledExceptionMapper.java

package jcg.zheng.demo.restfuljersey;

import static java.util.Collections.singletonMap;
import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;

import java.util.LinkedList;
import java.util.List;

import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import org.glassfish.jersey.spi.ExtendedExceptionMapper;

@Provider
public class UnhandledExceptionMapper implements ExtendedExceptionMapper<Exception> {
	private List<Class<? extends Exception>> filteredExceptions = new LinkedList<Class<? extends Exception>>();

	/*
	 * All ReST services should catch exceptions and repackage them as WebApplicationException
     * or more specific subclass.
	 */
	@Override
	public Response toResponse(final Exception e) {
		if (e instanceof WebApplicationException) {			
			if (e instanceof InternalServerErrorException) {
				return Response.status(INTERNAL_SERVER_ERROR).entity(singletonMap("error", "UNEXPECTED_ERROR")).build();
			}

			final WebApplicationException exception = (WebApplicationException) e;
			return exception.getResponse();
		}

		return Response.status(INTERNAL_SERVER_ERROR).entity(singletonMap("error", "UNEXPECTED_ERROR" + buildErrorMessage(e))).build();

	}

	@Override
	public boolean isMappable(final Exception exception) {
		for (Class<? extends Exception> filteredException : filteredExceptions) {
			if (filteredException.isAssignableFrom(exception.getClass())) {
				return false;
			}
		}

		return true;
	}
	
	  private String buildErrorMessage(Exception exception) {
	        return exception.getClass().getSimpleName() + ": " + exception.getMessage();
	    }

}

Second, I will create JerseyConfig which extends from org.glassfish.jersey.server.ResourceConfig and registers it with UserResourceImpl and UnhandledExceptionMapper.

JerseyConfig.java

package jcg.zheng.demo.restfuljersey;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.springframework.stereotype.Component;

import jcg.zheng.demo.restfuljersey.rest.impl.UserResourceImpl;

@Component
public class JerseyConfig extends ResourceConfig {
	public JerseyConfig() {
		registerApplicationProperties();
		registerApplicationApis();
	}

	private void registerApplicationApis() {
		register(UserResourceImpl.class);
		register(UnhandledExceptionMapper.class);
	}

	private void registerApplicationProperties() {		
		property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true);
		property(ServerProperties.BV_DISABLE_VALIDATE_ON_EXECUTABLE_OVERRIDE_CHECK, true);
	}
}

Lastly, I will update SpringBootJerseyDemoApplication which extends from org.springframework.boot.web.support.SpringBootServletInitializer.

SpringBootJerseyDemoApplication.java

package jcg.zheng.demo.restfuljersey;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@EnableJpaRepositories(basePackages = "jcg.zheng.demo.restfuljersey")
public class SpringBootJerseyDemoApplication extends SpringBootServletInitializer {

	public static void main(String[] args) {		
		new SpringBootJerseyDemoApplication().configure(new SpringApplicationBuilder(SpringBootJerseyDemoApplication.class))
				.run(args);
	}
}

4. Jersey Application Packages

I like to organize the application into eight packages:

  • rest – define the web service interfaces with JAX-RS API annotations
  • rest.impl – annotate @Component and implement the resource interface
  • service – define service to manage the data
  • service.impl – annotate @Service and implement the service interface
  • repository – annotate with Spring Data JPA @Repository to manage the entities
  • mapper – annotate with Spring @Component and converts between domain and entity
  • entity – Spring JPA entities
  • exception – RESTful web service exceptions

4.1 Rest

We will define the RESTful resource interface UserResource.java with JAX-RS annotations.

UserResource.java

package jcg.zheng.demo.restfuljersey.rest;

import java.util.List;

import javax.validation.Valid;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

@Path("/users")
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public interface UserResource {

	@GET
	List getUsers(@QueryParam("companyName") String companyName);

	@GET
	@Path(value = "/{userId}")
	User findUserById(@PathParam("userId") int userId);

	@POST
	User createUser(@Valid User request);

	@PUT	
	@Path(value = "/{userId}")
	User updateUser( @PathParam("userId")Integer userId, @Valid User request);

	@DELETE	
	@Path(value = "/{userId}")
	void deleteUser(@PathParam("userId")Integer userId);
}

We will create the User model class too.

User.java

package jcg.zheng.demo.restfuljersey.rest;

import javax.validation.constraints.NotNull;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class User {

	private Integer userId;

	@NotNull
	private String firstName;

	@NotNull
	private String lastName;

	@NotNull
	private String companyName;

	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 getCompanyName() {
		return companyName;
	}

	public void setCompanyName(String companyName) {
		this.companyName = companyName;
	}

	public Integer getUserId() {
		return userId;
	}

	public void setUserId(Integer userId) {
		this.userId = userId;
	}

 
}

We will create the implementation class UserResourceImpl and annotate it with @Component, so Spring context can manage it.

UserResourceImpl.java

package jcg.zheng.demo.restfuljersey.rest.impl;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import jcg.zheng.demo.restfuljersey.exception.UserNotFoundException;
import jcg.zheng.demo.restfuljersey.rest.User;
import jcg.zheng.demo.restfuljersey.rest.UserResource;
import jcg.zheng.demo.restfuljersey.service.UserService;

@Component
public class UserResourceImpl implements UserResource {

	@Autowired
	private UserService userService;

	public List<User> getUsers(String companyName) {
		return userService.searchByCompanyName(companyName);

	}

	@Override
	public User findUserById(int userId) {
		User found = userService.findById(userId);
		if (found == null) {
			throw new UserNotFoundException("invalid userId: " + userId);
		}
		return found;
	}

	@Override
	public User createUser(User request) {
		User saved = userService.save(request);
		return saved;
	}

	@Override
	public User updateUser(Integer userId, User request) {
		User found = userService.findById(userId);
		if (found == null) {
			throw new UserNotFoundException("invalid userId: " + userId);
		}
		if (!StringUtils.isEmpty(request.getCompanyName())) {
			found.setCompanyName(request.getCompanyName());
		}
		
		if (!StringUtils.isEmpty(request.getFirstName())) {
			found.setFirstName(request.getFirstName());
		}
		
		if (!StringUtils.isEmpty(request.getLastName())) {
			found.setLastName(request.getLastName());
		}
		return userService.save(found);
	}

	@Override
	public void deleteUser(Integer userId) {
		User found = userService.findById(userId);
		if (found == null) {
			throw new UserNotFoundException("invalid userId: " + userId);
		}
		userService.deleteById(userId);
	}

}

4.2 Service

In this step, we will create a UserService interface with four methods.

UserService.java

package jcg.zheng.demo.restfuljersey.service;

import java.util.List;

import jcg.zheng.demo.restfuljersey.rest.User;

public interface UserService {

	User save(User user);

	User findById(Integer personId);

	List<User> searchByCompanyName(String companyName);

	void deleteById(Integer personId);

}

We will create the implementation class UserServiceImpl.

UserServiceImpl.java

package jcg.zheng.demo.restfuljersey.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import jcg.zheng.demo.restfuljersey.entity.Person;
import jcg.zheng.demo.restfuljersey.mapper.UserConverter;
import jcg.zheng.demo.restfuljersey.repository.PersonRepository;
import jcg.zheng.demo.restfuljersey.rest.User;
import jcg.zheng.demo.restfuljersey.service.UserService;

@Component
@Transactional
public class UserServiceImpl implements UserService {

	@Autowired
	private PersonRepository personRepo;

	@Autowired
	private UserConverter mapper;

	@Override
	public User save(User user) {
		Person saved = personRepo.save(mapper.toEntity(user));
		return mapper.toDomain(saved);
	}

	@Override
	public User findById(Integer personId ) {
		if( personId.intValue() < 0 ) {
			throw new RuntimeException("Caught unhandle runtime");
		}
		Person found = personRepo.findOne(personId);
		if( found != null) {
			return mapper.toDomain(found);
		}
		return null;
	}

	@Override
	public List<User> searchByCompanyName(String companyName) {
		List<Person> persons = personRepo.findByCompany(companyName);
		List<User> users = new ArrayList<>();
		for (Person person:persons) {
			users.add(mapper.toDomain(person));
		}
		return users;
	}
	
	@Override
	public void deleteById(Integer personId) {
		personRepo.delete(personId);
	}
}

4.3 Repository

In this step, we will create a PersonRepository to manage the Person entity.

PersonRepository.java

package jcg.zheng.demo.restfuljersey.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import jcg.zheng.demo.restfuljersey.entity.Person;

@Repository
public interface PersonRepository extends JpaRepository<Person, Integer> {

	@Query("SELECT person from Person person WHERE person.companyName = :companyName")
	List<Person> findByCompany(@Param("companyName") String companyName);

}

4.4 Mapper

It is a good practice to never return the entity model to the client. Instead, we will create a UserConverter to convert between the User and Person.

UserConverter.java

package jcg.zheng.demo.restfuljersey.mapper;

import org.springframework.stereotype.Component;

import jcg.zheng.demo.restfuljersey.entity.Person;
import jcg.zheng.demo.restfuljersey.rest.User;

@Component
public class UserConverter {

	public Person toEntity(final User user) {
		Person person = new Person();
		person.setCompanyName(user.getCompanyName());
		person.setfName(user.getFirstName());
		person.setlName(user.getLastName());
		if (user.getUserId() != null) {
			person.setPersonId(user.getUserId());
		}
		return person;
	}

	public User toDomain(final Person person) {
		User user = new User();
		user.setCompanyName(person.getCompanyName());
		user.setFirstName(person.getfName());
		user.setLastName(person.getlName());
		user.setUserId(person.getPersonId());
		return user;
	}
}

4.5 Entity

We will create Person to model the user’s database entity.

Person.java

package jcg.zheng.demo.restfuljersey.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Person {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int personId;

	private String fName;
	private String lName;
	private String companyName;
	private String mName;

	public String getCompanyName() {
		return companyName;
	}

	public void setCompanyName(String companyName) {
		this.companyName = companyName;
	}

	public int getPersonId() {
		return personId;
	}

	public void setPersonId(int personId) {
		this.personId = personId;
	}

	public String getfName() {
		return fName;
	}

	public void setfName(String fName) {
		this.fName = fName;
	}

	public String getlName() {
		return lName;
	}

	public void setlName(String lName) {
		this.lName = lName;
	}

	public String getmName() {
		return mName;
	}

	public void setmName(String mName) {
		this.mName = mName;
	}

}

4.6 Exception

We will create a UserNotFoundException for any service when it cannot find the desired person.

UserNotFoundException.java

package jcg.zheng.demo.restfuljersey.exception;

import static java.util.Collections.singletonMap;

import javax.ws.rs.NotFoundException;
import javax.ws.rs.core.Response;

public class UserNotFoundException extends NotFoundException{

	private static final long serialVersionUID = 3873418545077760440L;

	public UserNotFoundException(String message) {		
		super(Response.status(Response.Status.NOT_FOUND).entity(singletonMap("error", message)).build());
	}
}

5. Start Spring Boot Application

Start the web application with the command java -jar target\spring-boot-jersey-demo-0.0.1-SNAPSHOT.

Confirm that the web application is up and running by viewing the server output.

Server output

 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::       (v1.5.14.RELEASE)

2018-07-11 23:16:49.273  INFO 29288 --- [           main] j.z.d.r.SpringBootJerseyDemoApplication  : Starting SpringBootJerseyDemoApplication on SL2LS431841 with PID 29288 (C:\gitworkspace\spring-boot-jersey-demo\target\classes started by Shu.Shan in C:\gitworkspace\spring-boot-jersey-demo)
2018-07-11 23:16:49.280  INFO 29288 --- [           main] j.z.d.r.SpringBootJerseyDemoApplication  : No active profile set, falling back to default profiles: default
2018-07-11 23:16:49.430  INFO 29288 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@3f200884: startup date [Wed Jul 11 23:16:49 CDT 2018]; root of context hierarchy
2018-07-11 23:16:50.912  INFO 29288 --- [           main] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2018-07-11 23:16:52.254  INFO 29288 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat initialized with port(s): 8080 (http)
2018-07-11 23:16:52.315  INFO 29288 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-07-11 23:16:52.316  INFO 29288 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.31
2018-07-11 23:16:52.912  INFO 29288 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-07-11 23:16:52.912  INFO 29288 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 3488 ms
2018-07-11 23:16:53.360  INFO 29288 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-07-11 23:16:53.361  INFO 29288 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-07-11 23:16:53.361  INFO 29288 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Mapping servlet: 'jcg.zheng.demo.restfuljersey.JerseyConfig' to [/*]
2018-07-11 23:16:54.024  INFO 29288 --- [           main] j.LocalContainerEntityManagerFactoryBean : Building JPA container EntityManagerFactory for persistence unit 'default'
2018-07-11 23:16:54.055  INFO 29288 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [
	name: default
	...]
2018-07-11 23:16:54.172  INFO 29288 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate Core {5.0.12.Final}
2018-07-11 23:16:54.174  INFO 29288 --- [           main] org.hibernate.cfg.Environment            : HHH000206: hibernate.properties not found
2018-07-11 23:16:54.177  INFO 29288 --- [           main] org.hibernate.cfg.Environment            : HHH000021: Bytecode provider name : javassist
2018-07-11 23:16:54.250  INFO 29288 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.0.1.Final}
2018-07-11 23:16:54.579  INFO 29288 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2018-07-11 23:16:55.208  INFO 29288 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000227: Running hbm2ddl schema export
2018-07-11 23:16:55.234  INFO 29288 --- [           main] org.hibernate.tool.hbm2ddl.SchemaExport  : HHH000230: Schema export complete
2018-07-11 23:16:55.297  INFO 29288 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2018-07-11 23:16:55.624  INFO 29288 --- [           main] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
2018-07-11 23:16:56.134  INFO 29288 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-07-11 23:16:56.183  INFO 29288 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-07-11 23:16:56.189  INFO 29288 --- [           main] j.z.d.r.SpringBootJerseyDemoApplication  : Started SpringBootJerseyDemoApplication in 7.348 seconds (JVM running for 7.844)

6. Java Clients

There are many ways to build a Java client to invoke the RESTful service. The most common ones are:

6.1 JaxRsClient

In this step, we will use javax.ws.rs.client.Client to send a POST request to create a new user.

JaxRsClient.java

package jcg.zheng.demo.restfuljersey.client;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import jcg.zheng.demo.restfuljersey.rest.User;

public class JaxRsClient {

	public static void main(String[] argus) {

		Client client = ClientBuilder.newClient();

		WebTarget target = client.target(ClientDataConstants.USER_URI);

		User data = ClientDataConstants.createDummyUser();
		
		Response ret = target.request().post(Entity.entity(data, MediaType.APPLICATION_JSON));
		System.out.println("Create User status: " + ret.getStatus());
		
		String output = ret.readEntity(String.class);
		System.out.println("Create User with output: " + output);

	}

}

Execute JaxRsClient as a Java application and you will see the output below:

JaxRsClient output

Create User status: 200
Create User with output: {"userId":1,"firstName":"Mary","lastName":"Zheng","companyName":"JCG"}

6.2 JerseyClient

In this step, we will use org.glassfish.jersey.client.JerseyClient to send a GET request to the users that belong to the “JCG” company.

Jersey2Client.java

package jcg.zheng.demo.restfuljersey.client;

import javax.ws.rs.core.Response;

import org.glassfish.jersey.client.JerseyClient;
import org.glassfish.jersey.client.JerseyClientBuilder;

public class Jersey2Client {

	public static void main(String[] argus) {

		JerseyClient client = JerseyClientBuilder.createClient();

		Response response = client.target(ClientDataConstants.USER_URI
				+"?companyName=JCG").request().get();

		System.out.println("Get User status " + response.getStatus());	 

		String output = response.readEntity(String.class);
		System.out.println("Find User with output: " + output);
	}
}

Execute Jersey2Client as a Java application and you will see the output below:

Jersey2Client output

Get User status 200
Find User with output: [{"userId":1,"firstName":"Mary","lastName":"Zheng","companyName":"JCG"}]

6.3 SpringRestTemplate

In this step, we will utilize org.springframework.web.client.RestTemplate to send a POST request to create a new user.

SpringRestClient.java

package jcg.zheng.demo.restfuljersey.client;

import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import jcg.zheng.demo.restfuljersey.rest.User;

public class SpringRestClient {

	public static void main(String[] args) {
		RestTemplate restTemplate = new RestTemplate();
	
		HttpEntity entity = new HttpEntity(ClientDataConstants.createDummyUser());

		ResponseEntity response = restTemplate.exchange(ClientDataConstants.USER_URI, HttpMethod.POST, entity,
				String.class);
		
		System.out.println("Create User status: " + response.getStatusCode());

		System.out.println("Create User: " + response.getBody());

	}

}

Execute SpringRestClient as a Java application and you will see the output below:

SpringRestClient output

23:26:58.513 [main] DEBUG org.springframework.web.client.RestTemplate - Created POST request for "http://localhost:8080/users"
23:26:58.518 [main] DEBUG org.springframework.web.client.RestTemplate - Setting request Accept header to 
23:26:58.547 [main] DEBUG org.springframework.web.client.RestTemplate - Writing [jcg.zheng.demo.restfuljersey.rest.User@64f6106c] using [org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter@553a3d88]
23:26:58.681 [main] DEBUG org.springframework.web.client.RestTemplate - POST request for "http://localhost:8080/users" resulted in 200 (null)
23:26:58.682 [main] DEBUG org.springframework.web.client.RestTemplate - Reading [java.lang.String] as "application/json" using [org.springframework.http.converter.StringHttpMessageConverter@103f852]
Create User status: 200
Create User: {"userId":2,"firstName":"Mary","lastName":"Zheng","companyName":"JCG"}

7. Summary

In this example, we created four Spring boot web services utilizing Spring boot, Spring JPA, and Jersey framework in six short steps:

  1. Generate the Spring boot Jersey JAX-RS project via the starter tool
  2. Add the User model classes
  3. Add the UserResource class
  4. Register UserResource in Jersey
  5. Start the Spring boot Jersey application
  6. Test the web services

8. Download the Source Code

This example consists of a Spring boot Jersey RESTful web services application as a Maven project.

Download
You can download the full source code of this example here: JAX-RS Tutorial with Jersey for RESTful Web Services

Mary Zheng

Mary has graduated from Mechanical Engineering department at ShangHai JiaoTong University. She also holds a Master degree in Computer Science from Webster University. During her studies she has been involved with a large number of projects ranging from programming and software engineering. She works as a senior Software Engineer in the telecommunications sector where she acts as a leader and works with others to design, implement, and monitor the software solution.
Subscribe
Notify of
guest

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

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Jun Zhang
Jun Zhang
5 years ago

very helpful for me. just one thing that there is a class ClientDataConstants is missing.
eg.
public class ClientDataConstants {
public static String USER_URI = “http://localhost:8080/users”;
public static User createDummyUser() {
//create a dummy user
User user = new User();

return user;
}
}

Back to top button