RESTful Web Services with Jersey and Spring Data JPA – Cheat Sheet

Create a Servlet Container deployable Jersey web application

Create new Jersey web application using Maven. The project created with the below jersey-quickstart-webapp archetype can be built and deployed to a servlet container like for example Apache Tomcat.

mvn archetype:generate -DarchetypeGroupId=org.glassfish.jersey.archetypes \
    -DarchetypeArtifactId=jersey-quickstart-webapp -DarchetypeVersion=2.26

POM.XML Dependency to Support JSON

To support JSON in your Jersey Web App add the following to a POM.xml file inside of <dependencies></dependencies> XML element.

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-binding</artifactId>
</dependency>

Sample Root Resource Class

The below is the example of Root Resource class that defines 4 most commonly used HTTP methods: POST, GET, PUT and DELETE.

HTTP POST – to create a new record
HTTP GET – to read an existing record
HTTP PUT – to update an existing record
HTTP DELETE – to delete an existing record

package com.appsdeveloperblog.app.ws.ui.entrypoints;

import com.appsdeveloperblog.app.ws.ui.model.request.CreateUserModelRest;
import com.appsdeveloperblog.app.ws.ui.model.request.UpdateUserModelRest;
import com.appsdeveloperblog.app.ws.ui.model.response.UserProfileRest;
import java.util.ArrayList;
import java.util.List;
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.core.MediaType;

/**
 * Root resource (exposed at "users" path)
 */
@Path("users")
public class Users {
    
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    @Path("/test")
    public String getIt() {
        return "Working!";
    }
    
    @GET
    @Produces({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
    public List<UserProfileRest> getUsers() {
        List<UserProfileRest> returnValue = new ArrayList<>();
        return returnValue;
    }
    
    @POST
    @Consumes({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
    @Produces({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
    public UserProfileRest createUser(CreateUserModelRest createUserModel) {
        UserProfileRest returnValue = new UserProfileRest();
        return returnValue;
    }
    
    @PUT
    @Path("/{id}")
    @Consumes({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
    @Produces({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
    public UserProfileRest updateUser(@PathParam("id") String id, 
            UpdateUserModelRest createUserModel) {
        UserProfileRest returnValue = new UserProfileRest();
        return returnValue;
    }
    
    @DELETE
    @Path("/{id}")
    @Consumes({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
    @Produces({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
    public UserProfileRest deleteUser(@PathParam("id") String id) {
        UserProfileRest returnValue = new UserProfileRest();
        return returnValue;
    }
    
}

Below are some other video courses that might help you learn how to build RESTful Web Services with Java. Have a look! I hope you will find one of them helpful.

URL Query Request Parameter Annotations

@QueryParam

When our web service entry point receives HTTP request which contains URL Query String Request Parameters we can read these request parameters using the @QueryParam annotation.

Below is an example of getUsers() resource method which reads the query string request parameters and if one is empty provides a default value using the @DefaultValue annotation.

@QueryParam – to read URL query parameter
@DefaultValue – to provide a default value if request parameter is not provided.

URL query string example: /users?start=0&limit=100

   @GET
   @Produces({ MediaType.APPLICATION_JSON,  MediaType.APPLICATION_XML} )
   public List<UserProfileRest> getUsers(@DefaultValue("0") @QueryParam("start") int start, 
           @DefaultValue("50") @QueryParam("limit") int limit) {
       List<UserProfileRest> returnValue = new ArrayList<>();
       
       List<UserProfileDto> users = userService.getUsers(start, limit);
        
       // Prepare return value 
       for (UserProfileDto userDto : users) {
           UserProfileRest userModel = new UserProfileRest();
           BeanUtils.copyProperties(userDto, userModel);
           returnValue.add(userModel);
       }
         
       return returnValue;
   }

Below are some video courses that might help you learn how to build RESTful Web Services with Java. Have a look! I hope you will find one of them helpful.

@PathParam annotation

Another very commonly used in RESTful Web Services parameter-based annotation is @PathParam. You will use @PathParam to read the request parameter included in the path of resource URL.

For example to get details of a particular user the path might look like this: /users/4hfyrhd73ld84ls84jfbd where the unique alpha-numeric string is a public userId.

@Path(“/{id}”)  – to annotate resource method with
@PathParam – to be used in method arguments list

Below is an example of resource method that reads path parameter.

@GET
@Path("/{id}")
@Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML } ) 
public UserProfileRest getUser(@PathParam("id") String id)
{
    UserProfileRest returnValue = new UserProfileRest();;
 
    UserProfileDto userProfile = userService.getUser(id);      
 
    BeanUtils.copyProperties(userProfile, returnValue);
    
    return returnValue;
}

Adding Spring Data JPA to Jersey 2 JAX-RS Web App

POM.XML Dependencies

Open with your favorite IDE the created with the above maven definition Jersey 2 Web app and update it’s pom.xml file. Below is my pom.xml file which contains dependencies for:

  • Jersey 2
  • Spring Framework
  • Spring Data JPA
  • Hibernate
  • MySQL database
<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/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>ru.altair</groupId>
    <artifactId>jersey_jpa</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>jersey_jpa</name>

    <build>
        <finalName>jersey_jpa</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <inherited>true</inherited>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.glassfish.jersey</groupId>
                <artifactId>jersey-bom</artifactId>
                <version>${jersey.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <!-- use the following artifactId if you don't need servlet 2.x compatibility -->
            <!-- artifactId>jersey-container-servlet</artifactId -->
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-binding</artifactId>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.ext</groupId>
            <artifactId>jersey-spring4</artifactId>
            <version>2.26</version>
        </dependency>

        <!--Spring Framework Dependencies-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>${spring-data.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Hibernate Dependencies -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

        <!-- Database Dependencies -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.187</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>


    </dependencies>
    <properties>
        <jersey.version>2.26</jersey.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.3.4.RELEASE</spring.version>
        <spring-data.version>1.10.5.RELEASE</spring-data.version>
        <hibernate.version>5.2.5.Final</hibernate.version>
    </properties>
</project>

WEB-XML File

It is very important up update the WEB-XML file to contain the below details:

  • contextConfigLocation with the location of you beans xml file,
  • Set up the ContextLoaderListener and the RequestContextListener,
  • Configure the jersey.config.server.provider.packagesspecify to specify which packages to scan,
  • And configure the URL pattern to specify the root URL path of your Web Service.
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
     see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/root-context.xml</param-value>
    </context-param>

    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>Jersey Web Application</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>jersey.config.server.provider.packages</param-name>
            <param-value>com.appsdeveloperblog.app.ws</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Jersey Web Application</servlet-name>
        <url-pattern>/webapi/*</url-pattern>
    </servlet-mapping>
</web-app>

Spring Root Context XML file

The location of this file is specified in the above WEB-XML file.  I have placed it in /WEB-XML/spring folder.

I also configure here the location of application.properties file which contains the database connection details and also other the Hibernate related properties.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:task="http://www.springframework.org/schema/task"
       xmlns:sec="http://www.springframework.org/schema/security"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
                           http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd">

    <context:component-scan base-package="com.appsdeveloperblog.app.ws" />

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="ignoreResourceNotFound" value="true"/>
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
        <property name="locations">
            <list>
                <value>classpath:application.properties</value>
                <value>file:${catalina.base}/conf/Catalina/localhost/application.properties</value>
            </list>
        </property>
    </bean>

    <import resource="classpath:db-context.xml"/>
</beans>

application.properties file

The application.properties file is also mentioned in the above beans XML file. In my project, this file is located in /src/main/resources folder. This application.properties file contains the details needed to connect to MySQL database and also the Hibernate properties to make our Jersey 2 Web app be able to use Spring Data JPA and to use hibernate and persist data into MySQL database.

#Database properties:
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/photo_app
db.username=sergey
db.password=sergey

#Hibernate Configuration:
db.hibernate.dialect=org.hibernate.dialect.MySQLDialect
db.hibernate.show_sql=true
db.entitymanager.packages.to.scan=com.appsdeveloperblog.app.ws
db.hibernate.hbm2ddl.auto=update

db-context.xml file

The location of this db-context.xml file is in /src/main/resources folder and is right next to the application.properties file.

In this file we define the:

  • dataSource bean
  • entityManagerFactory bean
  • transactionManager bean
  • we specify that our application is annotation driven
  • and we specify the base package for Spring Data JPA Repositories
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xsi:schemaLocation="
    http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/data/jpa
    http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${db.driver}" />
        <property name="url" value="${db.url}" />
        <property name="username" value="${db.username}" />
        <property name="password" value="${db.password}" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan" value="${db.entitymanager.packages.to.scan}"/>
        <property name="persistenceProviderClass" value="org.hibernate.jpa.HibernatePersistenceProvider"/>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.dialect">${db.hibernate.dialect}</prop>
                <prop key="hibernate.jdbc.time_zone">UTC</prop>
                <prop key="db.hibernate.show_sql">${db.hibernate.show_sql}</prop>
                <prop key="db.hibernate.hbm2ddl.auto">${db.hibernate.hbm2ddl.auto}</prop>
            </props>
        </property>
    </bean>

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>
    <tx:annotation-driven />

    <jpa:repositories base-package="com.appsdeveloperblog.app.ws" />
    <context:annotation-config />
</beans>

And this is all we need to do for configuration. Is it not very straightforward if you are just starting with Web Services Development and this is your first time working with Spring Framework and Jersey at the same time.

Below I will provide source code to my Root Resouce class, Service class, Entity object that needs to be persisted into MySQL database and the CrudRepository interface. I will also attach the source code to this project so that you can download it. Update the database connection details and run it to see how it works.

Root Resouce Class example

I have created only two methods here. One for creating a new user and one for returning a list of all users. It is just a sample code, so do not be too picky that I am not returning a correct Response object here and I do not handle runtime exceptions.

Since my application is annotation driven please note the annotations I used here.

package com.appsdeveloperblog.app.ws.ui.entrypoints;

import com.appsdeveloperblog.app.ws.service.impl.UserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.appsdeveloperblog.app.ws.shared.dto.UserDto;
import com.appsdeveloperblog.app.ws.ui.model.request.SaveUserRequest;
import com.appsdeveloperblog.app.ws.ui.model.response.UserRest;
import java.util.ArrayList;
import java.util.List;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import org.springframework.beans.BeanUtils;
 
@Component
@Path("users")
public class UsersEntryPoint {

    @Autowired
    UserServiceImpl springService;
 
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<UserRest> getAllUsers() {
       
        List<UserRest> returnValue = new ArrayList();
        List<UserDto> foundUsers = springService.getAllUsers();
        
        for(UserDto userDto:foundUsers)
        {
            UserRest userRest = new UserRest();
            BeanUtils.copyProperties(userDto, userRest);
            returnValue.add(userRest);
        }
        return returnValue;
    }

    @POST
    @Produces(MediaType.TEXT_PLAIN)
    public String save(SaveUserRequest saveUserRequest) {
       UserDto userDto = new UserDto(); 
       BeanUtils.copyProperties(saveUserRequest, userDto);
 
       springService.save(userDto);
 
       return "Ok";
    }
 
}

Service class

This class Authowires the Spring Data JPA CrudRespository interface.

package com.appsdeveloperblog.app.ws.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.appsdeveloperblog.app.ws.io.entities.UserEntity;
import com.appsdeveloperblog.app.ws.io.repositories.UserRepository;
import com.appsdeveloperblog.app.ws.service.UserService;
import com.appsdeveloperblog.app.ws.shared.dto.UserDto;
import com.appsdeveloperblog.app.ws.shared.exceptions.UserServiceException;
import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;
import org.glassfish.jersey.internal.guava.Lists;
import org.springframework.beans.BeanUtils;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    UserRepository userRepository;

    @PostConstruct
    private void init() {
    }

    @Override
    public List<UserDto> getAllUsers() {
        List<UserDto> returnValue = new ArrayList();
        
       List<UserEntity> foundRecords = Lists.newArrayList(userRepository.findAll());
       
       for(UserEntity userEntity:foundRecords)
       {
            UserDto userDto = new UserDto();
            BeanUtils.copyProperties(userEntity, userDto);
            returnValue.add(userDto);
       }
        
        return returnValue;
    }
 

    @Override
    public void save(UserDto userDto) throws UserServiceException {
   
        UserEntity userEntity = new UserEntity();
        BeanUtils.copyProperties(userDto, userEntity);
        
        // Perform needed validation and other required business logic here
        // Set other required fields like enctypted password for example
        String encryptedPassword = "encrypted password here";
        
        userEntity.setEncryptedPassword(encryptedPassword);
        
        try {
            userRepository.save(userEntity);
        } catch (Exception ex) {
            throw new UserServiceException(ex.getMessage());
        }
    }

}

Entity class

package com.appsdeveloperblog.app.ws.io.entities;

import javax.persistence.*;
 
@Entity(name = "Users")
public class UserEntity {

    @Id
    @GeneratedValue
    private Long id;

    private String firstName;
    private String lastName;
    private String email;
    private String encryptedPassword;
 

    public Long getId() {
        return id;
    }

    public UserEntity setId(Long id) {
        this.id = id;
        return this;
    }

    public String getFirstName() {
        return firstName;
    }

    public UserEntity setFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    public String getLastName() {
        return lastName;
    }

    public UserEntity setLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

    /**
     * @return the email
     */
    public String getEmail() {
        return email;
    }

    /**
     * @param email the email to set
     */
    public void setEmail(String email) {
        this.email = email;
    }

    /**
     * @return the encryptedPassword
     */
    public String getEncryptedPassword() {
        return encryptedPassword;
    }

    /**
     * @param encryptedPassword the encryptedPassword to set
     */
    public void setEncryptedPassword(String encryptedPassword) {
        this.encryptedPassword = encryptedPassword;
    }
}