RESTful Web Services Example in Java with Jersey, Spring and MyBatis


Codever Logo

(P) Codever is an open source bookmarks and snippets manager for developers & co. See our How To guides to help you get started. Public bookmarks repos on Github ⭐🙏


Note: At the time of writing this post I was just starting with REST and Jersey so I  suggest you have a look at  Tutorial – REST API design and implementation in Java with Jersey and Spring instead. My gained REST knowledge will be from now on reflected in this post, which is already an “(r)evolution” regarding REST API design, REST best practices used and backend architecture/implementation supporting the REST API presented in the tutorial.

Looking to REST? In Java? There’s never time for that :), but if you are looking to use an “architectural style consisting of a coordinated set of constraints applied to components, connectors, and data elements, within a distributed hypermedia system” in Java, then you have come to the right place, because in this post I will present a simple RESTful API that maps REST calls to backend services offering CRUD functionality.

Note: I will not focus too much on Representational state transfer (REST) itself, because there are plenty of resources on the topic in the internet, some of which I listed under Resources at the end of the post.

1. The example

1.1. Why?

My intention is to move some of the parts from Podcastpedia.org, that are currently implemented in Spring MVC, to JavaScript-land and for that I’ll need to use more backend REST web services. Of course I could use Spring’s own REST implementation, as I currently do for the AJAX calls, but I wanted also to see how the “official” implementation looks like.

Note: You can visit my post Autocomplete search box with jQuery and Spring MVC to see how Spring handles REST requests.

1.2. What does it do?

So, the best way to get to know the technology is build a prototype with it. And that’s exactly what I did and what I will present in this post. I’ve build a simple application that “manages” podcasts via a REST API. It does CRUD operations on a single database table (Podcasts), triggered via the REST web services API. Though fairly simple, the example highlights the most common annotations you’ll need to build your own REST API.

1.3. Architecture and technologies

Demo architecture

1.3.1. Jersey

The architecture is straightforward: with any REST client you can call the application’s API exposed via Jersey RESTful Web Services in JAVA. The Jersey RESTful Web Services framework is open source, production quality, framework for developing RESTful Web Services in Java that provides support for JAX-RS APIs and serves as a JAX-RS (JSR 311 & JSR 339) Reference Implementation.

1.3.2. Spring

I like glueing stuff together with Spring, and this example is no exception. You’ll find out how Jersey 2 integrates with Spring.

1.3.3. MyBatis

For the persistence layer, I chose Mybatis because I like it the most and it integrates fairly easy with Spring (see my post Spring MyBatis integration example for more on that), but you are free to choose any framework and technology you’re familiar with (e.g. JPA/Hibernate, Hibernate, JDBC etc).

Note: If you want to see how the persistence layer is implemented for the same application with JPA2 and Hibernate 4 see the post Java Persistence Example with Spring, JPA2 and Hibernate.

1.3.4. Web Container

Everything gets packaged as a .war file and can be deployed on any web container – I used Tomcat and Jetty but, it could also be Glassfih, Weblogic, JBoss or WebSphere.

1.3.5. MySQL

The sample data is stored in a MySQL table:

database schema

Note: The main focus in the post will be on the Jersey JAX-RS implementation, all the other technologies are viewed as enablers.

1.3.6. Technologies

  1. Jersey 2.4
  2. Spring 3.2
  3. Maven 3
  4. Tomcat 7
  5. Jetty 9
  6. MySql 5.6

1.3.7. Follow along

If you want to follow along, you find all you need on GitHub:

2. The coding

2.1. Configuration

2.1.1. Project dependencies

Among other things you need to have Jersey Spring extension in your project’s classpath. You can easily add that with Maven by having the following dependencies to the pom.xml file of the project:

<dependency>
	<groupId>org.glassfish.jersey.ext</groupId>
	<artifactId>jersey-spring3</artifactId>
	<version>2.4.1</version>
	<exclusions>
		<exclusion>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
		</exclusion>
		<exclusion>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
		</exclusion>
		<exclusion>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>org.glassfish.jersey.media</groupId>
	<artifactId>jersey-media-json-jackson</artifactId>
	<version>2.4.1</version>
</dependency>

Note: The jersey-spring3.jar, uses its own version for Spring libraries, so to use the ones you want, you need to exclude these libraries manually.

Code alert: If you want to see what other dependencies are used (for Spring, Jetty, testing) in the project or how Jetty is configured so that you can start the project directly in Jetty, you can download the complete pom.xml file from GitHub – https://github.com/adi-matei/demo-restWS-spring-jersey-tomcat-mybatis/blob/master/pom.xml

2.1.2. Web Application Deployment Descriptor – web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="https://java.sun.com/xml/ns/javaee"
	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
	<display-name>Demo - Restful Web Application</display-name>

	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring/applicationContext.xml</param-value>
	</context-param>

	<servlet>
		<servlet-name>jersey-serlvet</servlet-name>
		<servlet-class>
			org.glassfish.jersey.servlet.ServletContainer
		</servlet-class>
		<init-param>
			<param-name>javax.ws.rs.Application</param-name>
			<param-value>org.codingpedia.demo.rest.service.MyApplication</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>jersey-serlvet</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

	<resource-ref>
        <description>Database resource rest demo web application </description>
        <res-ref-name>jdbc/restDemoDB</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
</web-app>
2.1.2.1. Jersey-servlet

Notice the Jersey servlet configuration [lines 18-33]. The javax.ws.rs.core.Application class defines the components of the JAX-RS application. Because I extended the Application (ResourceConfig) class to provide the list of relevant root resource classes (getResources()) and singletons (getSingletons()), i.e. the JAX-RS application model, I needed to register it in my web application web.xml deployment descriptor using a Servlet or Servlet filter initialization parameter with a name of javax.ws.rs.Application.Check out the documentation for other possibilities.

The implementation of org.codingpedia.demo.rest.service.MyApplication looks like the following in the project:

package org.codingpedia.demo.rest.service;

import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.spring.scope.RequestContextFilter;

/**
 * Registers the components to be used by the JAX-RS application
 *
 * @author ama
 *
 */
public class MyDemoApplication extends ResourceConfig {

    /**
	* Register JAX-RS application components.
	*/
	public MyDemoApplication(){
		register(RequestContextFilter.class);
		register(PodcastRestService.class);
		register(JacksonFeature.class);
	}
}

The class registers the following components

  • org.glassfish.jersey.server.spring.scope.RequestContextFilter, which is a Spring filter that provides a bridge between JAX-RS and Spring request attributes
  • org.codingpedia.demo.rest.service.PodcastRestService, which is the service component that exposes the REST API via annotations, will be presented later in detail
  • org.glassfish.jersey.jackson.JacksonFeature, which is a feature that registers Jackson JSON providers – you need it for the application to understand JSON data
  • 2.1.2.2. Spring application context configuration

    The Spring application context configuration is located in the classpath under spring/applicationContext.xml:

    <beans xmlns="https://www.springframework.org/schema/beans"
    	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    	xmlns:context="https://www.springframework.org/schema/context"
    	xmlns:tx="https://www.springframework.org/schema/tx"
    	xsi:schemaLocation="
    		https://www.springframework.org/schema/beans
    		https://www.springframework.org/schema/beans/spring-beans.xsd
    
    		https://www.springframework.org/schema/tx
    		https://www.springframework.org/schema/tx/spring-tx.xsd
    
    		https://www.springframework.org/schema/context
    		https://www.springframework.org/schema/context/spring-context.xsd">
    
    	<context:component-scan base-package="org.codingpedia.demo.rest.*" />
    
    	<!--
    		Instruct Spring to perform declarative transaction management
    		automatically on annotated classes.
    	-->
    	<tx:annotation-driven transaction-manager="transactionManager" />
        <bean id="transactionManager"
              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
    	<!-- =============== MyBATIS beans configuration ================== -->
    	<bean id="podcastDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
    	   <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    	   <property name="mapperInterface" value="org.codingpedia.demo.rest.dao.PodcastDao" />
    	</bean>
    
    	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	    <property name="dataSource" ref="dataSource" />
    	    <property name="configLocation" value="classpath:config/mybatisV3.xml"/>
    	</bean>
    
        <bean id="podcastRestService" class="org.codingpedia.demo.rest.service.PodcastRestService" />
    
    	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
    	    <property name="jndiName" value="java:comp/env/jdbc/restDemoDB" />
    	    <property name="resourceRef" value="true" />
    	</bean>
    </beans>

    Nothing special here, it just defines the beans that are needed throughout the demo application. The most important one is the podcastRestService which is actually the entry point class for our RESTful API, and will be thouroughly described in the next paragraphs.

    2.2. The RESTful API

    2.2.1. Resources

    As mentioned earlier, the demo application manages podcasts, which represent the resources in our web API. Resources are the central concept in REST and are characterized by two main things:

    • each is referenced with a global identifier (e.g. a URI in HTTP).
    • has one or more representations, that they expose to the outer world and can be manipulated with (we’ll be working mostly with JSON representations in this example)

    The podcast resources are represented in our application by the Podcast class:

    package org.codingpedia.demo.rest.entities;
    
    import java.io.Serializable;
    import java.util.Date;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    /**
     * Podcast entity
     *
     * @author ama
     *
     */
    @XmlRootElement
    public class Podcast implements Serializable {
    
    	private static final long serialVersionUID = -8039686696076337053L;
    
    	/** id of the podcas */
    	private Long id;
    
    	/** title of the podcast */
    	private String title;
    
    	/** link of the podcast on Podcastpedia.org */
    	private String linkOnPodcastpedia;
    
    	/** url of the feed */
    	private String feed;
    
    	/** description of the podcast */
    	private String description;
    
    	/** when an episode was last published on the feed*/
    	private Date insertionDate;
    
    	public Podcast(){}
    
    	public Podcast(String title, String linkOnPodcastpedia, String feed,
    			String description) {
    
    		this.title = title;
    		this.linkOnPodcastpedia = linkOnPodcastpedia;
    		this.feed = feed;
    		this.description = description;
    
    	}
    
    	public String getTitle() {
    		return title;
    	}
    
    	public void setTitle(String title) {
    		this.title = title;
    	}
    
    	public String getLinkOnPodcastpedia() {
    		return linkOnPodcastpedia;
    	}
    
    	public void setLinkOnPodcastpedia(String linkOnPodcastpedia) {
    		this.linkOnPodcastpedia = linkOnPodcastpedia;
    	}
    
    	public String getDescription() {
    		return description;
    	}
    
    	public void setDescription(String description) {
    		this.description = description;
    	}
    
    	public Long getId() {
    		return id;
    	}
    
    	public void setId(Long id) {
    		this.id = id;
    	}
    
    	public String getFeed() {
    		return feed;
    	}
    
    	public void setFeed(String feed) {
    		this.feed = feed;
    	}
    
    	public Date getInsertionDate() {
    		return insertionDate;
    	}
    
    	public void setInsertionDate(Date insertionDate) {
    		this.insertionDate = insertionDate;
    	}
    
    }

    The strucuture is pretty simple – there are an id, which identifies a podcast, and several other fields that we’ll can see in the JSON representation:

    {
    	"id":1,
    	"title":"Quarks & Co - zum Mitnehmen-modified",
    	"linkOnPodcastpedia":"https://github.com/CodepediaOrg/podcastpedia/podcasts/1/Quarks-Co-zum-Mitnehmen",
    	"feed":"https://podcast.wdr.de/quarks.xml",
    	"description":"Quarks & Co: Das Wissenschaftsmagazin",
    	"insertionDate":1388213547000
    }

    2.2.2. Methods

    The API exposed by our example is described in the following table:

    Resource URI Method

    CREATE

    Add a list podcasts /podcasts/list

    POST

    Add a new podcast /podcasts/

    POST

    READ

    List of all podcasts /podcasts/

    GET

    List a single podcast /podcasts/{id}

    GET

    UPDATE

    Updates a single podcasts or creates one if not existent /podcasts/{id}

    PUT

    DELETE

    Delete all podcasts /podcasts/

    DELETE

    Delete a single podcast /podcasts/{id}

    DELETE

    As already mentioned the PodcastRestService class is the one handling all the rest requests:

    package org.codingpedia.demo.rest.service;
    ......................
    @Component
    @Path("/podcasts")
    public class PodcastRestService {
    
    	private static final String HOST = "http://localhost:8080/demo-rest-spring-jersey-tomcat-mybatis-0.0.1-SNAPSHOT";
    
    	@Autowired
    	private PodcastDao podcastDao;
    	......................
    }

    Notice the @Path("/podcasts") before the class definition. The @Path annotation’s value is a relative URI path. In the example above, the Java class will be hosted at the URI path /podcasts. The PodcastDao interface is used to communicate with the database.

    Code alert: You can find the entire content of the class on GitHub – https://github.com/adi-matei/demo-restWS-spring-jersey-tomcat-mybatis/blob/master/src/main/java/org/codingpedia/demo/rest/service/PodcastRestService.java. We’ll be going through the file step by step and explain the different methods corresponding to the different operations.

    2.2.2.1. CREATE

    For the creation of new resources(“podcasts”) I use the POST (HTTP) method.

    Note: In JAX-RS (Jersey) you specifies the HTTP methods (GET, POST, PUT, DELETE) by placing the corresponding annotation in front of the method.

    2.2.2.1.1. Create a single resource (“podcast”) from JSON input
    /**
     * Adds a new resource (podcast) from the given json format (at least title and feed elements are required
     * at the DB level)
     *
     * @param podcast
     * @return
     */
    @POST
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.TEXT_HTML})
    @Transactional
    public Response createPodcast(Podcast podcast) {
    	Long id = podcastDao.createPodcast(podcast);
    
    	return Response.status(201).entity(buildNewPodcastResourceURL(id)).build();
    }

    Annotations

    • <code>@POST</code> – indicates that the method responds to HTTP POST requests
    • @Consumes({MediaType.APPLICATION_JSON}) – defines the media type, the method accepts, in this case "application/json"
  • @Produces({MediaType.TEXT_HTML}) – defines the media type) that the method can produce, in this case "text/html". The response will be a html document, with a status of 201, indicating to the caller that the request has been fulfilled and resulted in a new resource being created.
  • @Transactional – Spring annotation, specifies that the method execution, should take place inside a transaction
  • 2.2.2.1.2. Create multiple resources (“podcasts”) from JSON input
    /**
    	 * A list of resources (here podcasts) provided in json format will be added
    	 * to the database.
    	 *
    	 * @param podcasts
    	 * @return
    	 */
    	@POST @Path("list")
    	@Consumes({MediaType.APPLICATION_JSON})
    	@Transactional
    	public Response createPodcasts(List<Podcast> podcasts) {
    		for(Podcast podcast : podcasts){
    			podcastDao.createPodcast(podcast);
    		}
    
    		return Response.status(204).build();
    	}

    Annotations

    • @POST – indicates that the method responds to HTTP POST requests
  • @Path("/list") – identifies the URI path that the class method will serve requests for. Paths are relative. The combined path here will be "/podcasts/list", because as we have seen we have @Path annotation at the class level
    • @Consumes({MediaType.APPLICATION_JSON}) – defines the media type, the method accepts, in this case "application/json"
  • @Transactional– Spring annotation, specifies that the method execution, should take place inside a transaction
  • In this case the method returns a status of 204 (“No Content”), suggesting that the server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation.

    2.2.2.1.3. Create a single resource (“podcast”) from form
    /**
     * Adds a new resource (podcast) from "form" (at least title and feed elements are required
     * at the DB level)
     *
     * @param title
     * @param linkOnPodcastpedia
     * @param feed
     * @param description
     * @return
     */
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces({MediaType.TEXT_HTML})
    @Transactional
    public Response createPodcastFromForm(
    					@FormParam("title") String title,
    					@FormParam("linkOnPodcastpedia") String linkOnPodcastpedia,
    					@FormParam("feed") String feed,
    					@FormParam("description") String description
    					) {
    	Podcast podcast = new Podcast(title, linkOnPodcastpedia, feed, description);
    	Long id = podcastDao.createPodcast(podcast);
    
    	return Response.status(201).entity(buildNewPodcastResourceURL(id)).build();
    }

    Annotations

    • @POST – indicates that the method responds to HTTP POST requests
  • @Consumes({MediaType.APPLICATION_FORM_URLENCODED})
        – defines the media type, the method accepts, in this case

    "application/x-www-form-urlencoded"

    • @FormParam – present before the input parameters of the method, this annotation binds the value(s) of a form parameter contained within a request entity body to a resource method parameter. Values are URL decoded unless this is disabled using the Encoded annotation
  • <code>@Produces({MediaType.TEXT_HTML}) - defines the media type) that the method can produce, in this case "text/html". The response will be a html document, with a status of 201, indicating to the caller that the request has been fulfilled and resulted in a new resource being created.</code>
    • @Transactional – Spring annotation, specifies that the method execution, should take place inside a transaction
    2.2.2.2. READ
    2.2.2.2.1. Read all resources
    /**
     * Returns all resources (podcasts) from the database
     * @return
     */
    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public List<Podcast> getPodcasts() {
    	return podcastDao.getPodcasts();
    }

    Annotations

    • ``<p class="note_alert" style="text-align: justify;"> Note: At the time of writing this post I was just starting with REST and Jersey so I  suggest you have a look at  Tutorial – REST API design and implementation in Java with Jersey and Spring instead. My gained REST knowledge will be from now on reflected in this post, which is already an “(r)evolution” regarding REST API design, REST best practices used and backend architecture/implementation supporting the REST API presented in the tutorial.

    </p>

    Looking to REST? In Java? There’s never time for that :), but if you are looking to use an “architectural style consisting of a coordinated set of constraints applied to components, connectors, and data elements, within a distributed hypermedia system” in Java, then you have come to the right place, because in this post I will present a simple RESTful API that maps REST calls to backend services offering CRUD functionality.

    Note: I will not focus too much on Representational state transfer (REST) itself, because there are plenty of resources on the topic in the internet, some of which I listed under Resources at the end of the post.

    1. The example

    1.1. Why?

    My intention is to move some of the parts from Podcastpedia.org, that are currently implemented in Spring MVC, to JavaScript-land and for that I’ll need to use more backend REST web services. Of course I could use Spring’s own REST implementation, as I currently do for the AJAX calls, but I wanted also to see how the “official” implementation looks like.

    Note: You can visit my post Autocomplete search box with jQuery and Spring MVC to see how Spring handles REST requests.

    1.2. What does it do?

    So, the best way to get to know the technology is build a prototype with it. And that’s exactly what I did and what I will present in this post. I’ve build a simple application that “manages” podcasts via a REST API. It does CRUD operations on a single database table (Podcasts), triggered via the REST web services API. Though fairly simple, the example highlights the most common annotations you’ll need to build your own REST API.

    1.3. Architecture and technologies

    Demo architecture

    1.3.1. Jersey

    The architecture is straightforward: with any REST client you can call the application’s API exposed via Jersey RESTful Web Services in JAVA. The Jersey RESTful Web Services framework is open source, production quality, framework for developing RESTful Web Services in Java that provides support for JAX-RS APIs and serves as a JAX-RS (JSR 311 & JSR 339) Reference Implementation.

    1.3.2. Spring

    I like glueing stuff together with Spring, and this example is no exception. You’ll find out how Jersey 2 integrates with Spring.

    1.3.3. MyBatis

    For the persistence layer, I chose Mybatis because I like it the most and it integrates fairly easy with Spring (see my post Spring MyBatis integration example for more on that), but you are free to choose any framework and technology you’re familiar with (e.g. JPA/Hibernate, Hibernate, JDBC etc).

    Note: If you want to see how the persistence layer is implemented for the same application with JPA2 and Hibernate 4 see the post Java Persistence Example with Spring, JPA2 and Hibernate.

    1.3.4. Web Container

    Everything gets packaged as a .war file and can be deployed on any web container – I used Tomcat and Jetty but, it could also be Glassfih, Weblogic, JBoss or WebSphere.

    1.3.5. MySQL

    The sample data is stored in a MySQL table:

    database schema

    Note: The main focus in the post will be on the Jersey JAX-RS implementation, all the other technologies are viewed as enablers.

    1.3.6. Technologies

    1. Jersey 2.4
    2. Spring 3.2
    3. Maven 3
    4. Tomcat 7
    5. Jetty 9
    6. MySql 5.6

    1.3.7. Follow along

    If you want to follow along, you find all you need on GitHub:

    2. The coding

    2.1. Configuration

    2.1.1. Project dependencies

    Among other things you need to have Jersey Spring extension in your project’s classpath. You can easily add that with Maven by having the following dependencies to the pom.xml file of the project:

    <dependency>
    	<groupId>org.glassfish.jersey.ext</groupId>
    	<artifactId>jersey-spring3</artifactId>
    	<version>2.4.1</version>
    	<exclusions>
    		<exclusion>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-core</artifactId>
    		</exclusion>
    		<exclusion>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-web</artifactId>
    		</exclusion>
    		<exclusion>
    			<groupId>org.springframework</groupId>
    			<artifactId>spring-beans</artifactId>
    		</exclusion>
    	</exclusions>
    </dependency>
    <dependency>
    	<groupId>org.glassfish.jersey.media</groupId>
    	<artifactId>jersey-media-json-jackson</artifactId>
    	<version>2.4.1</version>
    </dependency>

    Note: The jersey-spring3.jar, uses its own version for Spring libraries, so to use the ones you want, you need to exclude these libraries manually.

    Code alert: If you want to see what other dependencies are used (for Spring, Jetty, testing) in the project or how Jetty is configured so that you can start the project directly in Jetty, you can download the complete pom.xml file from GitHub – https://github.com/adi-matei/demo-restWS-spring-jersey-tomcat-mybatis/blob/master/pom.xml

    2.1.2. Web Application Deployment Descriptor – web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.0" xmlns="https://java.sun.com/xml/ns/javaee"
    	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
    	<display-name>Demo - Restful Web Application</display-name>
    
    	<listener>
    		<listener-class>
    			org.springframework.web.context.ContextLoaderListener
    		</listener-class>
    	</listener>
    
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>classpath:spring/applicationContext.xml</param-value>
    	</context-param>
    
    	<servlet>
    		<servlet-name>jersey-serlvet</servlet-name>
    		<servlet-class>
    			org.glassfish.jersey.servlet.ServletContainer
    		</servlet-class>
    		<init-param>
    			<param-name>javax.ws.rs.Application</param-name>
    			<param-value>org.codingpedia.demo.rest.service.MyApplication</param-value>
    		</init-param>
    		<load-on-startup>1</load-on-startup>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>jersey-serlvet</servlet-name>
    		<url-pattern>/*</url-pattern>
    	</servlet-mapping>
    
    	<resource-ref>
            <description>Database resource rest demo web application </description>
            <res-ref-name>jdbc/restDemoDB</res-ref-name>
            <res-type>javax.sql.DataSource</res-type>
            <res-auth>Container</res-auth>
        </resource-ref>
    </web-app>
    2.1.2.1. Jersey-servlet

    Notice the Jersey servlet configuration [lines 18-33]. The javax.ws.rs.core.Application class defines the components of the JAX-RS application. Because I extended the Application (ResourceConfig) class to provide the list of relevant root resource classes (getResources()) and singletons (getSingletons()), i.e. the JAX-RS application model, I needed to register it in my web application web.xml deployment descriptor using a Servlet or Servlet filter initialization parameter with a name of javax.ws.rs.Application.Check out the documentation for other possibilities.

    The implementation of org.codingpedia.demo.rest.service.MyApplication looks like the following in the project:

    package org.codingpedia.demo.rest.service;
    
    import org.glassfish.jersey.jackson.JacksonFeature;
    import org.glassfish.jersey.server.ResourceConfig;
    import org.glassfish.jersey.server.spring.scope.RequestContextFilter;
    
    /**
     * Registers the components to be used by the JAX-RS application
     *
     * @author ama
     *
     */
    public class MyDemoApplication extends ResourceConfig {
    
        /**
    	* Register JAX-RS application components.
    	*/
    	public MyDemoApplication(){
    		register(RequestContextFilter.class);
    		register(PodcastRestService.class);
    		register(JacksonFeature.class);
    	}
    }

    The class registers the following components

  • org.glassfish.jersey.server.spring.scope.RequestContextFilter, which is a Spring filter that provides a bridge between JAX-RS and Spring request attributes
  • org.codingpedia.demo.rest.service.PodcastRestService, which is the service component that exposes the REST API via annotations, will be presented later in detail
  • org.glassfish.jersey.jackson.JacksonFeature, which is a feature that registers Jackson JSON providers – you need it for the application to understand JSON data
  • 2.1.2.2. Spring application context configuration

    The Spring application context configuration is located in the classpath under spring/applicationContext.xml:

    <beans xmlns="https://www.springframework.org/schema/beans"
    	xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    	xmlns:context="https://www.springframework.org/schema/context"
    	xmlns:tx="https://www.springframework.org/schema/tx"
    	xsi:schemaLocation="
    		https://www.springframework.org/schema/beans
    		https://www.springframework.org/schema/beans/spring-beans.xsd
    
    		https://www.springframework.org/schema/tx
    		https://www.springframework.org/schema/tx/spring-tx.xsd
    
    		https://www.springframework.org/schema/context
    		https://www.springframework.org/schema/context/spring-context.xsd">
    
    	<context:component-scan base-package="org.codingpedia.demo.rest.*" />
    
    	<!--
    		Instruct Spring to perform declarative transaction management
    		automatically on annotated classes.
    	-->
    	<tx:annotation-driven transaction-manager="transactionManager" />
        <bean id="transactionManager"
              class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
    	<!-- =============== MyBATIS beans configuration ================== -->
    	<bean id="podcastDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
    	   <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
    	   <property name="mapperInterface" value="org.codingpedia.demo.rest.dao.PodcastDao" />
    	</bean>
    
    	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	    <property name="dataSource" ref="dataSource" />
    	    <property name="configLocation" value="classpath:config/mybatisV3.xml"/>
    	</bean>
    
        <bean id="podcastRestService" class="org.codingpedia.demo.rest.service.PodcastRestService" />
    
    	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean" scope="singleton">
    	    <property name="jndiName" value="java:comp/env/jdbc/restDemoDB" />
    	    <property name="resourceRef" value="true" />
    	</bean>
    </beans>

    Nothing special here, it just defines the beans that are needed throughout the demo application. The most important one is the podcastRestService which is actually the entry point class for our RESTful API, and will be thouroughly described in the next paragraphs.

    2.2. The RESTful API

    2.2.1. Resources

    As mentioned earlier, the demo application manages podcasts, which represent the resources in our web API. Resources are the central concept in REST and are characterized by two main things:

    • each is referenced with a global identifier (e.g. a URI in HTTP).
    • has one or more representations, that they expose to the outer world and can be manipulated with (we’ll be working mostly with JSON representations in this example)

    The podcast resources are represented in our application by the Podcast class:

    package org.codingpedia.demo.rest.entities;
    
    import java.io.Serializable;
    import java.util.Date;
    
    import javax.xml.bind.annotation.XmlRootElement;
    
    /**
     * Podcast entity
     *
     * @author ama
     *
     */
    @XmlRootElement
    public class Podcast implements Serializable {
    
    	private static final long serialVersionUID = -8039686696076337053L;
    
    	/** id of the podcas */
    	private Long id;
    
    	/** title of the podcast */
    	private String title;
    
    	/** link of the podcast on Podcastpedia.org */
    	private String linkOnPodcastpedia;
    
    	/** url of the feed */
    	private String feed;
    
    	/** description of the podcast */
    	private String description;
    
    	/** when an episode was last published on the feed*/
    	private Date insertionDate;
    
    	public Podcast(){}
    
    	public Podcast(String title, String linkOnPodcastpedia, String feed,
    			String description) {
    
    		this.title = title;
    		this.linkOnPodcastpedia = linkOnPodcastpedia;
    		this.feed = feed;
    		this.description = description;
    
    	}
    
    	public String getTitle() {
    		return title;
    	}
    
    	public void setTitle(String title) {
    		this.title = title;
    	}
    
    	public String getLinkOnPodcastpedia() {
    		return linkOnPodcastpedia;
    	}
    
    	public void setLinkOnPodcastpedia(String linkOnPodcastpedia) {
    		this.linkOnPodcastpedia = linkOnPodcastpedia;
    	}
    
    	public String getDescription() {
    		return description;
    	}
    
    	public void setDescription(String description) {
    		this.description = description;
    	}
    
    	public Long getId() {
    		return id;
    	}
    
    	public void setId(Long id) {
    		this.id = id;
    	}
    
    	public String getFeed() {
    		return feed;
    	}
    
    	public void setFeed(String feed) {
    		this.feed = feed;
    	}
    
    	public Date getInsertionDate() {
    		return insertionDate;
    	}
    
    	public void setInsertionDate(Date insertionDate) {
    		this.insertionDate = insertionDate;
    	}
    
    }

    The strucuture is pretty simple – there are an id, which identifies a podcast, and several other fields that we’ll can see in the JSON representation:

    {
    	"id":1,
    	"title":"Quarks & Co - zum Mitnehmen-modified",
    	"linkOnPodcastpedia":"https://github.com/CodepediaOrg/podcastpedia/podcasts/1/Quarks-Co-zum-Mitnehmen",
    	"feed":"https://podcast.wdr.de/quarks.xml",
    	"description":"Quarks & Co: Das Wissenschaftsmagazin",
    	"insertionDate":1388213547000
    }

    2.2.2. Methods

    The API exposed by our example is described in the following table:

    Resource URI Method

    CREATE

    Add a list podcasts /podcasts/list

    POST

    Add a new podcast /podcasts/

    POST

    READ

    List of all podcasts /podcasts/

    GET

    List a single podcast /podcasts/{id}

    GET

    UPDATE

    Updates a single podcasts or creates one if not existent /podcasts/{id}

    PUT

    DELETE

    Delete all podcasts /podcasts/

    DELETE

    Delete a single podcast /podcasts/{id}

    DELETE

    As already mentioned the PodcastRestService class is the one handling all the rest requests:

    package org.codingpedia.demo.rest.service;
    ......................
    @Component
    @Path("/podcasts")
    public class PodcastRestService {
    
    	private static final String HOST = "http://localhost:8080/demo-rest-spring-jersey-tomcat-mybatis-0.0.1-SNAPSHOT";
    
    	@Autowired
    	private PodcastDao podcastDao;
    	......................
    }

    Notice the @Path("/podcasts") before the class definition. The @Path annotation’s value is a relative URI path. In the example above, the Java class will be hosted at the URI path /podcasts. The PodcastDao interface is used to communicate with the database.

    Code alert: You can find the entire content of the class on GitHub – https://github.com/adi-matei/demo-restWS-spring-jersey-tomcat-mybatis/blob/master/src/main/java/org/codingpedia/demo/rest/service/PodcastRestService.java. We’ll be going through the file step by step and explain the different methods corresponding to the different operations.

    2.2.2.1. CREATE

    For the creation of new resources(“podcasts”) I use the POST (HTTP) method.

    Note: In JAX-RS (Jersey) you specifies the HTTP methods (GET, POST, PUT, DELETE) by placing the corresponding annotation in front of the method.

    2.2.2.1.1. Create a single resource (“podcast”) from JSON input
    /**
     * Adds a new resource (podcast) from the given json format (at least title and feed elements are required
     * at the DB level)
     *
     * @param podcast
     * @return
     */
    @POST
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.TEXT_HTML})
    @Transactional
    public Response createPodcast(Podcast podcast) {
    	Long id = podcastDao.createPodcast(podcast);
    
    	return Response.status(201).entity(buildNewPodcastResourceURL(id)).build();
    }

    Annotations

    • <code>@POST</code> – indicates that the method responds to HTTP POST requests
    • @Consumes({MediaType.APPLICATION_JSON}) – defines the media type, the method accepts, in this case "application/json"
  • @Produces({MediaType.TEXT_HTML}) – defines the media type) that the method can produce, in this case "text/html". The response will be a html document, with a status of 201, indicating to the caller that the request has been fulfilled and resulted in a new resource being created.
  • @Transactional – Spring annotation, specifies that the method execution, should take place inside a transaction
  • 2.2.2.1.2. Create multiple resources (“podcasts”) from JSON input
    /**
    	 * A list of resources (here podcasts) provided in json format will be added
    	 * to the database.
    	 *
    	 * @param podcasts
    	 * @return
    	 */
    	@POST @Path("list")
    	@Consumes({MediaType.APPLICATION_JSON})
    	@Transactional
    	public Response createPodcasts(List<Podcast> podcasts) {
    		for(Podcast podcast : podcasts){
    			podcastDao.createPodcast(podcast);
    		}
    
    		return Response.status(204).build();
    	}

    Annotations

    • @POST – indicates that the method responds to HTTP POST requests
  • @Path("/list") – identifies the URI path that the class method will serve requests for. Paths are relative. The combined path here will be "/podcasts/list", because as we have seen we have @Path annotation at the class level
    • @Consumes({MediaType.APPLICATION_JSON}) – defines the media type, the method accepts, in this case "application/json"
  • @Transactional– Spring annotation, specifies that the method execution, should take place inside a transaction
  • In this case the method returns a status of 204 (“No Content”), suggesting that the server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation.

    2.2.2.1.3. Create a single resource (“podcast”) from form
    /**
     * Adds a new resource (podcast) from "form" (at least title and feed elements are required
     * at the DB level)
     *
     * @param title
     * @param linkOnPodcastpedia
     * @param feed
     * @param description
     * @return
     */
    @POST
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces({MediaType.TEXT_HTML})
    @Transactional
    public Response createPodcastFromForm(
    					@FormParam("title") String title,
    					@FormParam("linkOnPodcastpedia") String linkOnPodcastpedia,
    					@FormParam("feed") String feed,
    					@FormParam("description") String description
    					) {
    	Podcast podcast = new Podcast(title, linkOnPodcastpedia, feed, description);
    	Long id = podcastDao.createPodcast(podcast);
    
    	return Response.status(201).entity(buildNewPodcastResourceURL(id)).build();
    }

    Annotations

    • @POST – indicates that the method responds to HTTP POST requests
  • @Consumes({MediaType.APPLICATION_FORM_URLENCODED})
        – defines the media type, the method accepts, in this case

    "application/x-www-form-urlencoded"

    • @FormParam – present before the input parameters of the method, this annotation binds the value(s) of a form parameter contained within a request entity body to a resource method parameter. Values are URL decoded unless this is disabled using the Encoded annotation
  • <code>@Produces({MediaType.TEXT_HTML}) - defines the media type) that the method can produce, in this case "text/html". The response will be a html document, with a status of 201, indicating to the caller that the request has been fulfilled and resulted in a new resource being created.</code>
    • @Transactional – Spring annotation, specifies that the method execution, should take place inside a transaction
    2.2.2.2. READ
    2.2.2.2.1. Read all resources
    /**
     * Returns all resources (podcasts) from the database
     * @return
     */
    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public List<Podcast> getPodcasts() {
    	return podcastDao.getPodcasts();
    }

    Annotations

    *`` – indicates that the method responds to HTTP GET requests

  • @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) – defines the media type) that the method can produce, in this case "application/json" or "application/xml"(you need the @XmlRootElement in front of the Podcast class to produce xml formatted response). The response will be a list of podcasts either in JSON or XML format.
  • 2.2.2.2.2. Read one resource
    @GET @Path("{id}")
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public Response findById(@PathParam("id") Long id) {
    	Podcast podcastById = podcastDao.getPodcastById(id);
    	if(podcastById != null) {
    		return Response.status(200).entity(podcastById).build();
    	} else {
    		return Response.status(404).entity("The podcast with the id " + id + " does not exist").build();
    	}
    }

    Annotations

    • @GET – indicates that the method responds to HTTP GET requests
  • @Path("{id}") – identifies the URI path that the class method will serve requests for. The “id” value is an embedded variable making an URI path template. It is used in combination with the @PathParam variable.
    • @PathParam("id") – binds the value of a URI template parameter (“id”) to the resource method parameter. The value is URL decoded unless this is di sabled using the @Encoded annotation. A default value can be specified using the @DefaultValue annotation.
  • @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) – defines the media type) that the method can produce, in this case "application/json" or "application/xml"(you need the @XmlRootElement in front of the Podcast class to produce the response in xml format). The response will be a podcast either in JSON or XML format with the “200 OK” status, or a message saying the podcast does not exit with a “404 Not Found” status.
  • 2.2.2.3. UPDATE
    /**
     * Updates the attributes of the podcast received via JSON for the given @param id
     *
     * If the podcast does not exist yet in the database (verified by <strong>id</strong>) then
     * the application will try to create a new podcast resource in the db
     *
     * @param id
     * @param podcast
     * @return
     */
    @PUT @Path("{id}")
    @Consumes({MediaType.APPLICATION_JSON})
    @Produces({MediaType.TEXT_HTML})
    @Transactional
    public Response updatePodcastById(@PathParam("id") Long id, Podcast podcast) {
    	if(podcast.getId() == null) podcast.setId(id);
    	String message;
    	int status;
    	if(podcastWasUpdated(podcast)){
    		status = 200; //OK
    		message = "Podcast has been updated";
    	} else if(podcastCanBeCreated(podcast)){
    		podcastDao.createPodcast(podcast);
    		status = 201; //Created
    		message = "The podcast you provided has been added to the database";
    	} else {
    		status = 406; //Not acceptable
    		message = "The information you provided is not sufficient to perform either an UPDATE or "
    				+ " an INSERTION of the new podcast resource <br/>"
    				+ " If you want to UPDATE please make sure you provide an existent <strong>id</strong> <br/>"
    				+ " If you want to insert a new podcast please provide at least a <strong>title</strong> and the <strong>feed</strong> for the podcast resource";
    	}
    
    	return Response.status(status).entity(message).build();
    }

    Annotations

    • @PUT– indicates that the method responds to HTTP PUT requests
  • @Path("{id}") – identifies the URI path that the class method will serve requests for. The “id” value is an embedded variable making an URI path template. It is used in combination with the @PathParam variable.
    • @PathParam("id") – binds the value of a URI template parameter (“id”) to the resource method parameter. The value is URL decoded unless this is di sabled using the @Encoded annotation. A default value can be specified using the @DefaultValue annotation.
  • @Consumes({MediaType.APPLICATION_JSON}) – defines the media type, the method accepts, in this case "application/json"
  • @Produces({MediaType.TEXT_HTML}) – defines the media type) that the method can produce, in this case “text/html”. The response will be a html document containing different messages and stati depending on what action has been taken
    • 200 – OK, “podcast updated successfully “
    • 201 – id given was not found in the db, so a new podcast resource has been created
    • 406 – if id was not found and you haven’t provided enough information for the creation of a new resource, the request is “Not Acceptable”
  • 2.2.2.4. DELETE
    2.2.2.4.1. Delete all resources
    @DELETE
    @Produces({MediaType.TEXT_HTML})
    public Response deletePodcasts() {
    	podcastDao.deletePodcasts();
    	return Response.status(200).entity("All podcasts have been successfully removed").build();
    }

    Annotations

    • @DELETE – indicates that the method responds to HTTP DELETE requests
  • @Produces({MediaType.TEXT_HTML}) – defines the media type that the method can produce, in this case “text/html”. The response will be a html document, with a status of 200, indicating to the caller that the request has been fulfilled.
    • @Transactional – Spring annotation, specifies that the method execution, should take place inside a transaction
    2.2.2.4.2. Delete one resource
    @DELETE @Path("{id}")
    @Produces({MediaType.TEXT_HTML})
    @Transactional
    public Response deletePodcastById(@PathParam("id") Long id) {
    	if(podcastDao.deletePodcastById(id) == 1){
    		return Response.status(204).build();
    	} else {
    		return Response.status(404).entity("Podcast with the id " + id + " is not present in the database").build();
    	}
    }</code>

    Annotations

    • @DELETE – indicates that the method responds to HTTP DELETE requests
    • @Path("{id}") – identifies the URI path that the class method will serve requests for. The “id” value is an embedded variable making an URI path template. It is used in combination with the @PathParam variable.
      • @PathParam("id") – binds the value of a URI template parameter (“id”) to the resource method parameter. The value is URL decoded unless this is di sabled using the @Encoded annotation. A default value can be specified using the @DefaultValue annotation.
    • @Produces({MediaType.TEXT_HTML}) – defines the media type that the method can produce, in this case “text/html”. If the podcast is deleted, that is found in the database, a 204 “No Content” success status is returnred, otherwise an html document with the status of 404 “Not found” is returned
    • @Transactional – Spring annotation, specifies that the method execution, should take place inside a transaction

    3. Testing

    3.1. Integration tests

    To test the application I will use the Jersey Client and execute requests against a running Jetty server with the application deployed on it. For that I will use the Maven Failsafe Plugin.

    3.1.1. Configuration

    3.1.1.1 Jersey client dependency

    To build a Jersey client the jersey-client jar is required in the classpath. With Maven you can add it as a dependency to the pom.xml file:

    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-client</artifactId>
        <version>2.4.1</version>
        <scope>test</scope>
    </dependency>
    3.1.1.2. Failsafe plugin

    The Failsafe Plugin is used during the integration-test and verify phases of the build lifecycle to execute the integration tests of the application. The Failsafe Plugin will not fail the build during the integration-test phase thus enabling the post-integration-test phase to execute.
    To use the Failsafe Plugin, you need to add the following configuration to your pom.xml

    <plugins>
    	[...]
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-failsafe-plugin</artifactId>
            <version>2.16</version>
            <executions>
                <execution>
                    <id>integration-test</id>
                    <goals>
                        <goal>integration-test</goal>
                    </goals>
                </execution>
                <execution>
                    <id>verify</id>
                    <goals>
                        <goal>verify</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    	[...]
    </plugins>
    3.1.1.2. Jetty Maven Plugin

    As mentioned, the integration tests will be executed against a running jetty server, that will be started only for the execution of the tests. For that the following execution has to be configured in the jetty-maven-plugin configuration:

    <plugins>
    	<plugin>
    		<groupId>org.eclipse.jetty</groupId>
    		<artifactId>jetty-maven-plugin</artifactId>
    		<version>${jetty.version}</version>
    		<configuration>
    			<jettyConfig>${project.basedir}/src/main/resources/config/jetty9.xml</jettyConfig>
    			<stopKey>STOP</stopKey>
    			<stopPort>9999</stopPort>
    			<stopWait>5</stopWait>
    			<scanIntervalSeconds>5</scanIntervalSeconds>
    		[...]
    		</configuration>
    		<executions>
    			<execution>
    				<id>start-jetty</id>
    				<phase>pre-integration-test</phase>
    				<goals>
    					<!-- stop any previous instance to free up the port -->
    					<goal>stop</goal>
    					<goal>run-exploded</goal>
    				</goals>
    				<configuration>
    					<scanIntervalSeconds>0</scanIntervalSeconds>
    					<daemon>true</daemon>
    				</configuration>
    			</execution>
    			<execution>
    				<id>stop-jetty</id>
    				<phase>post-integration-test</phase>
    				<goals>
    					<goal>stop</goal>
    				</goals>
    			</execution>
    		</executions>
    	</plugin>
    	[...]
    </plugins></code>

    Note: In the pre-integration-test phase the Jetty server will be started, after stopping any running instance to free up the port, and in the post-integration-phase it will be stopped. The scanIntervalSeconds has to be set to 0, and daemon to true.

    Code alert: See the complete pom.xml file on GitHub – https://github.com/adi-matei/demo-restWS-spring-jersey-tomcat-mybatis/blob/master/pom.xml

    3.1.2. Build the integration tests

    I am using JUnit as the testing framework. By default, the Failsafe Plugin will automatically include all test classes with the following wildcard patterns:

    • <tt>"**/IT*.java"</tt> – includes all of its subdirectories and all java filenames that start with “IT”.
    • <tt>"**/*IT.java"</tt> – includes all of its subdirectories and all java filenames that end with “IT”.
    • <tt>"**/*ITCase.java"</tt> – includes all of its subdirectories and all java filenames that end with “ITCase”.

    I have created a single test class – RestDemoServiceIT – that will test the read (GET) methods, but the procedure should be the same for all the other:

    public class RestDemoServiceIT {
    
    	[....]
    	@Test
    	public void testGetPodcast() throws JsonGenerationException,
    			JsonMappingException, IOException {
    
    		ClientConfig clientConfig = new ClientConfig();
    		clientConfig.register(JacksonFeature.class);
    
    		Client client = ClientBuilder.newClient(clientConfig);
    
    		WebTarget webTarget = client
    				.target("http://localhost:8888/demo-rest-spring-jersey-tomcat-mybatis-0.0.1-SNAPSHOT/podcasts/2");
    
    		Builder request = webTarget.request(MediaType.APPLICATION_JSON);
    
    		Response response = request.get();
    		Assert.assertTrue(response.getStatus() == 200);
    
    		Podcast podcast = response.readEntity(Podcast.class);
    
    		ObjectMapper mapper = new ObjectMapper();
    		System.out
    				.print("Received podcast from database *************************** "
    						+ mapper.writerWithDefaultPrettyPrinter()
    								.writeValueAsString(podcast));
    
    	}
    }

    Note:

    • I had to register the JacksonFeature for the client too so that I can marshall the podcast response in JSON format – response.readEntity(Podcast.class)
    • I am testing against a running Jetty on port 8888 – I will show you in the next section how to start Jetty on a desired port
    • I am expecting a 200 status for my request
    • With the help org.codehaus.jackson.map.ObjectMapper I am displaying the JSON response nicely formatted

    3.1.3. Running the integration tests

    The Failsafe Plugin can be invoked by calling the <tt>verify</tt> phase of the build lifecycle.

    mvn verify

    To start jetty on port 8888 you need to set the jetty.port property to 8888. In Eclipse I use the following configuration:

    Run integration tests from Eclipse

    Run integration tests from Eclipse

     

    3.2. Live tests

    In the following video I will will show how to test the API application from Chrome with the help of DEV HTTP Client, which I highly recommend:

    4. Summary

    Well, that’s it. You’ve learned how to create a REST API with the help of Jersey 2, how it integrates with Spring with the new jersey-spring3 dependency and how to test the API with the Jersey Client and from Chrome with the help of Dev HTTP Client.

    If you’ve found some usefulnes in this post, I’d be very grateful if you helped it spread by leaving a comment or sharing it on Twitter, Google+ or Facebook. Thank you! Don’t forget also to check out Podcastpedia.org – you’ll find for sure interesting podcasts and episodes. We are grateful for your support.

    5. Resources

    5.1. Source Code

    5.2. Web resources

    5.3. Codingpedia resources

    Podcastpedia image

    Adrian Matei

    Creator of Podcastpedia.org and Codepedia.org, computer science engineer, husband, father, curious and passionate about science, computers, software, education, economics, social equity, philosophy - but these are just outside labels and not that important, deep inside we are all just consciousness, right?
    Subscribe to our newsletter for more code resources and news

    Adrian Matei (aka adixchen)

    Adrian Matei (aka adixchen)
    Life force expressing itself as a coding capable human being

    routerLink with query params in Angular html template

    routerLink with query params in Angular html template code snippet Continue reading