diff --git a/pom.xml b/pom.xml
index c590183137..0b0351f462 100644
--- a/pom.xml
+++ b/pom.xml
@@ -117,6 +117,7 @@
spring-hibernate3
spring-hibernate4
spring-integration
+ spring-jersey
spring-jms
spring-jooq
spring-jpa
diff --git a/spring-jersey/.gitignore b/spring-jersey/.gitignore
new file mode 100644
index 0000000000..83c05e60c8
--- /dev/null
+++ b/spring-jersey/.gitignore
@@ -0,0 +1,13 @@
+*.class
+
+#folders#
+/target
+/neoDb*
+/data
+/src/main/webapp/WEB-INF/classes
+*/META-INF/*
+
+# Packaged files #
+*.jar
+*.war
+*.ear
\ No newline at end of file
diff --git a/spring-jersey/README.md b/spring-jersey/README.md
new file mode 100644
index 0000000000..2767ceb9a7
--- /dev/null
+++ b/spring-jersey/README.md
@@ -0,0 +1,3 @@
+=========
+
+## REST API with Jersey & Spring Example Project
diff --git a/spring-jersey/pom.xml b/spring-jersey/pom.xml
new file mode 100644
index 0000000000..00d67febec
--- /dev/null
+++ b/spring-jersey/pom.xml
@@ -0,0 +1,210 @@
+
+
+ 4.0.0
+
+ com.baeldung
+ jersey-api
+ 0.1-SNAPSHOT
+ war
+
+
+ 2.25
+ 1.7.22
+ 1.1.8
+ 4.12
+ 3.0.0
+ 2.19.1
+ 1.6.1
+ 4.12
+ 4.4.5
+ 4.5.2
+ 3.1.0
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.8
+ 1.8
+
+
+
+ maven-war-plugin
+ ${maven-war-plugin.version}
+
+ false
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ **/*IntegrationTest.java
+ **/*LiveTest.java
+
+
+
+
+
+ org.codehaus.cargo
+ cargo-maven2-plugin
+ ${cargo-maven2-plugin.version}
+
+ true
+
+ jetty8x
+ embedded
+
+
+
+ 8082
+
+
+
+
+
+
+
+
+
+
+
+
+ org.glassfish.jersey.core
+ jersey-server
+ ${jersey.version}
+
+
+ org.glassfish.jersey.containers
+ jersey-container-servlet
+ ${jersey.version}
+
+
+ org.glassfish.jersey.media
+ jersey-media-json-jackson
+ ${jersey.version}
+
+
+
+ javax.servlet
+ javax.servlet-api
+ ${servlet-api-version}
+ provided
+
+
+
+
+ org.glassfish.jersey.ext
+ jersey-spring3
+ ${jersey.version}
+
+
+ commons-logging
+ commons-logging
+
+
+
+
+
+ org.slf4j
+ jcl-over-slf4j
+ ${jcl.slf4j.version}
+
+
+
+ ch.qos.logback
+ logback-classic
+ ${logback.version}
+
+
+
+
+
+ org.apache.httpcomponents
+ httpclient
+ ${httpclient.version}
+ test
+
+
+
+ org.apache.httpcomponents
+ httpcore
+ ${httpcore.version}
+ test
+
+
+
+
+
+ junit
+ junit
+ ${junit.version}
+ test
+
+
+
+
+
+ live
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ integration-test
+
+ test
+
+
+
+ **/*IntegrationTest.java
+
+
+ **/*LiveTest.java
+
+
+
+
+
+
+ json
+
+
+
+
+ org.codehaus.cargo
+ cargo-maven2-plugin
+ ${cargo-maven2-plugin.version}
+
+ false
+
+
+
+ start-server
+ pre-integration-test
+
+ start
+
+
+
+ stop-server
+ post-integration-test
+
+ stop
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-jersey/src/main/java/com/baeldung/server/config/ApplicationInitializer.java b/spring-jersey/src/main/java/com/baeldung/server/config/ApplicationInitializer.java
new file mode 100644
index 0000000000..d91d4d5f38
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/config/ApplicationInitializer.java
@@ -0,0 +1,22 @@
+package com.baeldung.server.config;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.ContextLoaderListener;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+
+@Order(Ordered.HIGHEST_PRECEDENCE)
+public class ApplicationInitializer implements WebApplicationInitializer {
+
+ @Override
+ public void onStartup(ServletContext servletContext) throws ServletException {
+ AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
+ servletContext.addListener(new ContextLoaderListener(context));
+ servletContext.setInitParameter("contextConfigLocation", "com.baeldung.server");
+ }
+
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/config/RestConfig.java b/spring-jersey/src/main/java/com/baeldung/server/config/RestConfig.java
new file mode 100644
index 0000000000..34d8948f59
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/config/RestConfig.java
@@ -0,0 +1,19 @@
+package com.baeldung.server.config;
+
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+
+import com.baeldung.server.exception.AlreadyExistsExceptionHandler;
+import com.baeldung.server.exception.NotFoundExceptionHandler;
+import com.baeldung.server.rest.EmployeeResource;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+@ApplicationPath("/resources")
+public class RestConfig extends Application {
+ public Set> getClasses() {
+ return new HashSet>(Arrays.asList(EmployeeResource.class, NotFoundExceptionHandler.class, AlreadyExistsExceptionHandler.class));
+ }
+}
\ No newline at end of file
diff --git a/spring-jersey/src/main/java/com/baeldung/server/exception/AlreadyExistsExceptionHandler.java b/spring-jersey/src/main/java/com/baeldung/server/exception/AlreadyExistsExceptionHandler.java
new file mode 100644
index 0000000000..4603372807
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/exception/AlreadyExistsExceptionHandler.java
@@ -0,0 +1,12 @@
+package com.baeldung.server.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class AlreadyExistsExceptionHandler implements ExceptionMapper {
+ public Response toResponse(EmployeeAlreadyExists ex) {
+ return Response.status(Response.Status.CONFLICT.getStatusCode()).build();
+ }
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/exception/EmployeeAlreadyExists.java b/spring-jersey/src/main/java/com/baeldung/server/exception/EmployeeAlreadyExists.java
new file mode 100644
index 0000000000..827e4bf1e7
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/exception/EmployeeAlreadyExists.java
@@ -0,0 +1,5 @@
+package com.baeldung.server.exception;
+
+public class EmployeeAlreadyExists extends RuntimeException {
+
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/exception/EmployeeNotFound.java b/spring-jersey/src/main/java/com/baeldung/server/exception/EmployeeNotFound.java
new file mode 100644
index 0000000000..f205b5dfae
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/exception/EmployeeNotFound.java
@@ -0,0 +1,5 @@
+package com.baeldung.server.exception;
+
+public class EmployeeNotFound extends RuntimeException {
+
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/exception/NotFoundExceptionHandler.java b/spring-jersey/src/main/java/com/baeldung/server/exception/NotFoundExceptionHandler.java
new file mode 100644
index 0000000000..5de9b53c30
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/exception/NotFoundExceptionHandler.java
@@ -0,0 +1,12 @@
+package com.baeldung.server.exception;
+
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
+
+@Provider
+public class NotFoundExceptionHandler implements ExceptionMapper {
+ public Response toResponse(EmployeeNotFound ex) {
+ return Response.status(Response.Status.NOT_FOUND).build();
+ }
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/model/Employee.java b/spring-jersey/src/main/java/com/baeldung/server/model/Employee.java
new file mode 100644
index 0000000000..1801134f68
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/model/Employee.java
@@ -0,0 +1,34 @@
+package com.baeldung.server.model;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+public class Employee {
+ private int id;
+ private String firstName;
+
+ public Employee() {
+
+ }
+
+ public Employee(int id, String firstName) {
+ this.id = id;
+ this.firstName = firstName;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/repository/EmployeeRepository.java b/spring-jersey/src/main/java/com/baeldung/server/repository/EmployeeRepository.java
new file mode 100644
index 0000000000..15132cd618
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/repository/EmployeeRepository.java
@@ -0,0 +1,18 @@
+package com.baeldung.server.repository;
+
+import java.util.List;
+
+import com.baeldung.server.model.Employee;
+
+public interface EmployeeRepository {
+
+ public List getAllEmployees();
+
+ public Employee getEmployee(int id);
+
+ public void updateEmployee(Employee employee, int id);
+
+ public void deleteEmployee(int id);
+
+ public void addEmployee(Employee employee);
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/repository/EmployeeRepositoryImpl.java b/spring-jersey/src/main/java/com/baeldung/server/repository/EmployeeRepositoryImpl.java
new file mode 100644
index 0000000000..8e61e1395b
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/repository/EmployeeRepositoryImpl.java
@@ -0,0 +1,65 @@
+package com.baeldung.server.repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Component;
+
+import com.baeldung.server.exception.EmployeeAlreadyExists;
+import com.baeldung.server.exception.EmployeeNotFound;
+import com.baeldung.server.model.Employee;
+
+@Component
+public class EmployeeRepositoryImpl implements EmployeeRepository {
+ private List employeeList;
+
+ public EmployeeRepositoryImpl() {
+ employeeList = new ArrayList();
+ employeeList.add(new Employee(1, "Jane"));
+ employeeList.add(new Employee(2, "Jack"));
+ employeeList.add(new Employee(3, "George"));
+ }
+
+ public List getAllEmployees() {
+ return employeeList;
+ }
+
+ public Employee getEmployee(int id) {
+ for (Employee emp : employeeList) {
+ if (emp.getId() == id) {
+ return emp;
+ }
+ }
+ throw new EmployeeNotFound();
+ }
+
+ public void updateEmployee(Employee employee, int id) {
+ for (Employee emp : employeeList) {
+ if (emp.getId() == id) {
+ emp.setId(employee.getId());
+ emp.setFirstName(employee.getFirstName());
+ return;
+ }
+ }
+ throw new EmployeeNotFound();
+ }
+
+ public void deleteEmployee(int id) {
+ for (Employee emp : employeeList) {
+ if (emp.getId() == id) {
+ employeeList.remove(emp);
+ return;
+ }
+ }
+ throw new EmployeeNotFound();
+ }
+
+ public void addEmployee(Employee employee) {
+ for (Employee emp : employeeList) {
+ if (emp.getId() == employee.getId()) {
+ throw new EmployeeAlreadyExists();
+ }
+ }
+ employeeList.add(employee);
+ }
+}
diff --git a/spring-jersey/src/main/java/com/baeldung/server/rest/EmployeeResource.java b/spring-jersey/src/main/java/com/baeldung/server/rest/EmployeeResource.java
new file mode 100644
index 0000000000..2301f3eaf3
--- /dev/null
+++ b/spring-jersey/src/main/java/com/baeldung/server/rest/EmployeeResource.java
@@ -0,0 +1,64 @@
+package com.baeldung.server.rest;
+
+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.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baeldung.server.model.Employee;
+import com.baeldung.server.repository.EmployeeRepository;
+
+@Path("/employees")
+public class EmployeeResource {
+
+ @Autowired
+ private EmployeeRepository employeeRepository;
+
+ @GET
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public List getAllEmployees() {
+ return employeeRepository.getAllEmployees();
+ }
+
+ @GET
+ @Path("/{id}")
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Employee getEmployee(@PathParam("id") int id) {
+ return employeeRepository.getEmployee(id);
+ }
+
+ @PUT
+ @Path("/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response updateEmployee(Employee employee, @PathParam("id") int id) {
+ employeeRepository.updateEmployee(employee, id);
+ return Response.status(Response.Status.OK.getStatusCode()).build();
+ }
+
+ @DELETE
+ @Path("/{id}")
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response deleteEmployee(@PathParam("id") int id) {
+ employeeRepository.deleteEmployee(id);
+ return Response.status(Response.Status.OK.getStatusCode()).build();
+ }
+
+ @POST
+ @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ public Response addEmployee(Employee employee, @Context UriInfo uriInfo) {
+ employeeRepository.addEmployee(new Employee(employee.getId(), employee.getFirstName()));
+ return Response.status(Response.Status.CREATED.getStatusCode()).header("Location", String.format("%s/%s", uriInfo.getAbsolutePath().toString(), employee.getId())).build();
+ }
+}
diff --git a/spring-jersey/src/main/resources/logback.xml b/spring-jersey/src/main/resources/logback.xml
new file mode 100644
index 0000000000..788096686a
--- /dev/null
+++ b/spring-jersey/src/main/resources/logback.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ web - %date [%thread] %-5level %logger{36} -
+ %message%n
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/spring-jersey/src/test/java/com/baeldung/server/JerseyApiLiveTest.java b/spring-jersey/src/test/java/com/baeldung/server/JerseyApiLiveTest.java
new file mode 100644
index 0000000000..80c4e94b50
--- /dev/null
+++ b/spring-jersey/src/test/java/com/baeldung/server/JerseyApiLiveTest.java
@@ -0,0 +1,91 @@
+package com.baeldung.server;
+
+import java.io.IOException;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.junit.Test;
+
+import com.baeldung.server.model.Employee;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class JerseyApiLiveTest {
+
+ private static final String SERVICE_URL = "http://localhost:8082/jersey-api/resources/employees";
+
+ @Test
+ public void givenGetAllEmployees_whenCorrectRequest_thenResponseCodeSuccess() throws ClientProtocolException, IOException {
+ final HttpUriRequest request = new HttpGet(SERVICE_URL);
+
+ final HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
+
+ assert(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
+ }
+
+ @Test
+ public void givenGetEmployee_whenEmployeeExists_thenResponseCodeSuccess() throws ClientProtocolException, IOException {
+ final HttpUriRequest request = new HttpGet(SERVICE_URL + "/1");
+
+ final HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
+
+ assert(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK);
+ }
+
+ @Test
+ public void givenGetEmployee_whenEmployeeDoesNotExist_thenResponseCodeNotFound() throws ClientProtocolException, IOException {
+ final HttpUriRequest request = new HttpGet(SERVICE_URL + "/1000");
+
+ final HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
+
+ assert(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND);
+ }
+
+ @Test
+ public void givenGetEmployee_whenJsonRequested_thenCorrectDataRetrieved() throws ClientProtocolException, IOException {
+ final HttpUriRequest request = new HttpGet(SERVICE_URL + "/1");
+
+ request.setHeader("Accept", "application/json");
+ final HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
+ ObjectMapper mapper = new ObjectMapper();
+ Employee emp = mapper.readValue(httpResponse.getEntity().getContent(), Employee.class);
+
+ assert(emp.getFirstName().equals("Jane"));
+ }
+
+ @Test
+ public void givenAddEmployee_whenJsonRequestSent_thenResponseCodeCreated() throws ClientProtocolException, IOException {
+ final HttpPost request = new HttpPost(SERVICE_URL);
+
+ Employee emp = new Employee(5, "Johny");
+ ObjectMapper mapper = new ObjectMapper();
+ String empJson = mapper.writeValueAsString(emp);
+ StringEntity input = new StringEntity(empJson);
+ input.setContentType("application/json");
+ request.setEntity(input);
+ final HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
+
+ assert(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED);
+ }
+
+ @Test
+ public void givenAddEmployee_whenRequestForExistingObjectSent_thenResponseCodeConflict() throws ClientProtocolException, IOException {
+ final HttpPost request = new HttpPost(SERVICE_URL);
+
+ Employee emp = new Employee(1, "Johny");
+ ObjectMapper mapper = new ObjectMapper();
+ String empJson = mapper.writeValueAsString(emp);
+ StringEntity input = new StringEntity(empJson);
+ input.setContentType("application/json");
+ request.setEntity(input);
+ final HttpResponse httpResponse = HttpClientBuilder.create().build().execute(request);
+
+ assert(httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_CONFLICT);
+ }
+
+}
\ No newline at end of file