├── .gitignore ├── README.md ├── async-processing ├── pom.xml └── src │ └── main │ ├── java │ └── xpadro │ │ └── spring │ │ └── web │ │ ├── MainApp.java │ │ ├── controller │ │ ├── AsyncCallableController.java │ │ ├── AsyncDeferredController.java │ │ └── BlockingController.java │ │ └── service │ │ ├── TaskService.java │ │ └── TaskServiceImpl.java │ └── webapp │ └── WEB-INF │ └── web.xml ├── rest-controlleradvice ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── .jsdtscope │ ├── org.eclipse.jdt.core.prefs │ ├── org.eclipse.m2e.core.prefs │ ├── org.eclipse.wst.common.component │ ├── org.eclipse.wst.common.project.facet.core.xml │ ├── org.eclipse.wst.jsdt.ui.superType.container │ └── org.eclipse.wst.jsdt.ui.superType.name ├── pom.xml └── src │ ├── main │ ├── java │ │ ├── log4j.xml │ │ └── xpadro │ │ │ └── spring │ │ │ └── rest │ │ │ ├── controller │ │ │ ├── AddPersonController.java │ │ │ ├── GetPersonController.java │ │ │ ├── UpdatePersonController.java │ │ │ └── advice │ │ │ │ └── CentralControllerHandler.java │ │ │ ├── exception │ │ │ └── PersonNotFoundException.java │ │ │ ├── model │ │ │ └── Person.java │ │ │ ├── repository │ │ │ ├── PersonRepository.java │ │ │ └── impl │ │ │ │ └── PersonRepositoryImpl.java │ │ │ └── validator │ │ │ └── PersonValidator.java │ ├── resources │ │ └── xpadro │ │ │ └── spring │ │ │ └── rest │ │ │ └── configuration │ │ │ ├── app-context.xml │ │ │ └── root-context.xml │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ └── index.jsp │ └── test │ └── java │ └── xpadro │ └── spring │ └── rest │ └── client │ └── PersonRestServiceTesting.java ├── rest-converters ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── .jsdtscope │ ├── org.eclipse.jdt.core.prefs │ ├── org.eclipse.m2e.core.prefs │ ├── org.eclipse.wst.common.component │ ├── org.eclipse.wst.common.project.facet.core.xml │ ├── org.eclipse.wst.jsdt.ui.superType.container │ └── org.eclipse.wst.jsdt.ui.superType.name ├── pom.xml └── src │ ├── main │ ├── java │ │ └── xpadro │ │ │ └── spring │ │ │ └── rest │ │ │ ├── controller │ │ │ └── MvcRestController.java │ │ │ ├── model │ │ │ ├── Car.java │ │ │ └── User.java │ │ │ └── repository │ │ │ ├── CarRepository.java │ │ │ ├── UserRepository.java │ │ │ └── impl │ │ │ ├── CarRepositoryImpl.java │ │ │ └── UserRepositoryImpl.java │ ├── resources │ │ └── xpadro │ │ │ └── spring │ │ │ └── rest │ │ │ └── configuration │ │ │ ├── app-context.xml │ │ │ ├── db-context.xml │ │ │ └── root-context.xml │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ └── index.jsp │ └── test │ └── java │ └── xpadro │ └── spring │ └── rest │ └── client │ └── RestTesting.java ├── rest-subresources ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── .jsdtscope │ ├── org.eclipse.jdt.core.prefs │ ├── org.eclipse.m2e.core.prefs │ ├── org.eclipse.wst.common.component │ ├── org.eclipse.wst.common.project.facet.core.xml │ ├── org.eclipse.wst.jsdt.ui.superType.container │ └── org.eclipse.wst.jsdt.ui.superType.name ├── pom.xml └── src │ └── main │ ├── java │ └── xpadro │ │ └── rest │ │ └── ri │ │ ├── model │ │ ├── Item.java │ │ ├── TypeAItem.java │ │ └── TypeBItem.java │ │ ├── repository │ │ ├── TypeAItemRepository.java │ │ └── TypeBItemRepository.java │ │ └── resources │ │ ├── ItemResource.java │ │ ├── TypeAResource.java │ │ ├── TypeBResource.java │ │ └── WarehouseResource.java │ └── webapp │ ├── WEB-INF │ └── web.xml │ └── index.jsp ├── rest_test ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── .jsdtscope │ ├── org.eclipse.jdt.core.prefs │ ├── org.eclipse.wst.common.component │ ├── org.eclipse.wst.common.project.facet.core.xml │ ├── org.eclipse.wst.jsdt.ui.superType.container │ ├── org.eclipse.wst.jsdt.ui.superType.name │ └── org.maven.ide.eclipse.prefs ├── pom.xml └── src │ ├── main │ ├── java │ │ ├── log4j.xml │ │ └── xpadro │ │ │ └── tutorial │ │ │ └── rest │ │ │ ├── controller │ │ │ └── WarehouseController.java │ │ │ ├── exception │ │ │ └── ProductNotFoundException.java │ │ │ ├── model │ │ │ ├── Product.java │ │ │ └── Warehouse.java │ │ │ └── repository │ │ │ ├── WarehouseRepository.java │ │ │ └── WarehouseRepositoryImpl.java │ ├── resources │ │ └── xpadro │ │ │ └── tutorial │ │ │ └── rest │ │ │ └── configuration │ │ │ ├── app-context.xml │ │ │ └── root-context.xml │ └── webapp │ │ └── WEB-INF │ │ └── web.xml │ └── test │ └── java │ └── xpadro │ └── tutorial │ └── rest │ └── client │ └── TestWarehouse.java ├── spring-rest-api-v32 ├── .classpath ├── .gitignore ├── .project ├── .settings │ ├── .jsdtscope │ ├── org.eclipse.jdt.core.prefs │ ├── org.eclipse.m2e.core.prefs │ ├── org.eclipse.wst.common.component │ ├── org.eclipse.wst.common.project.facet.core.xml │ ├── org.eclipse.wst.jsdt.ui.superType.container │ ├── org.eclipse.wst.jsdt.ui.superType.name │ └── org.eclipse.wst.validation.prefs ├── pom.xml └── src │ ├── main │ ├── java │ │ ├── log4j.xml │ │ └── xpadro │ │ │ └── spring │ │ │ └── web │ │ │ ├── controller │ │ │ └── SeriesController.java │ │ │ ├── model │ │ │ └── Series.java │ │ │ └── service │ │ │ ├── SeriesService.java │ │ │ └── impl │ │ │ └── SeriesServiceImpl.java │ ├── resources │ │ └── xpadro │ │ │ └── spring │ │ │ └── web │ │ │ └── configuration │ │ │ ├── app-context.xml │ │ │ ├── db-context.xml │ │ │ └── root-context.xml │ └── webapp │ │ ├── WEB-INF │ │ └── web.xml │ │ └── index.jsp │ └── test │ ├── java │ └── xpadro │ │ └── spring │ │ └── web │ │ └── test │ │ ├── SeriesFunctionalTesting.java │ │ └── SeriesIntegrationTesting.java │ └── resources │ └── xpadro │ └── spring │ └── web │ └── test │ └── configuration │ └── test-root-context.xml └── spring-rest-api-v4 ├── .classpath ├── .gitignore ├── .project ├── .settings ├── .jsdtscope ├── org.eclipse.jdt.core.prefs ├── org.eclipse.m2e.core.prefs ├── org.eclipse.wst.common.component ├── org.eclipse.wst.common.project.facet.core.xml ├── org.eclipse.wst.jsdt.ui.superType.container ├── org.eclipse.wst.jsdt.ui.superType.name └── org.eclipse.wst.validation.prefs ├── environment └── development │ └── workspace │ └── spring-rest-api-v4 │ └── target │ └── m2e-wtp │ └── web-resources │ └── .gitignore ├── pom.xml └── src ├── main ├── java │ ├── log4j.xml │ └── xpadro │ │ └── spring │ │ └── web │ │ ├── controller │ │ └── SeriesController.java │ │ ├── model │ │ └── Series.java │ │ └── service │ │ ├── SeriesService.java │ │ └── impl │ │ └── SeriesServiceImpl.java ├── resources │ └── xpadro │ │ └── spring │ │ └── web │ │ └── configuration │ │ ├── app-context.xml │ │ ├── db-context.xml │ │ └── root-context.xml └── webapp │ ├── WEB-INF │ └── web.xml │ └── index.jsp └── test ├── java └── xpadro │ └── spring │ └── web │ └── test │ ├── SeriesAsyncCallableFunctionalTest.java │ ├── SeriesAsyncFunctionalTest.java │ ├── SeriesFunctionalBaseTests.java │ ├── SeriesFunctionalTest.java │ └── SeriesIntegrationTest.java └── resources └── xpadro └── spring └── web └── test └── configuration └── test-root-context.xml /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | spring-rest 2 | =========== 3 | 4 | Samples of RESTful web services using Spring MVC 5 | 6 | - rest_test: Implementation of RESTful web services using Spring MVC. The application controller contains several CRUD operations that are tested using the restTemplate class. 7 | 8 | Blog post related to this project: 9 | http://xpadro.com/2013/02/create-and-test-rest-services-with.html 10 | 11 | 12 | - rest-converters: This project shows how message converters work when using the RestTemplate class. Depending on which Object is returned by the controller, a different converter will be applied to the response body. 13 | 14 | Blog post related to this project: 15 | http://xpadro.com/2013/02/accessing-restful-services-http-message.html 16 | 17 | 18 | - rest-controlleradvice: Shows how to centralize exception handling from different controllers using the @ControllerAdvice annotation. 19 | 20 | Blog post related to this project: 21 | http://xpadro.com/2013/03/centralize-validation-and-exception.html 22 | 23 | 24 | - rest-subresources: This is a JAX-RS project that uses a subresource locator which decide at runtime what subresource will be returned. 25 | 26 | Blog post related to this project: 27 | http://xpadro.com/2013/05/handling-different-subresources-with.html 28 | 29 | 30 | - spring-rest-api-v32: A Spring MVC RESTful web application. This app implements a REST API which accesses a MongoDB database in order to handle data from TV series. It also contains examples on how to implement integration tests (mockMvc) and functional tests (restTemplate). This project has been implemented in Spring 3.2.3 version and has been used as a base to implement the spring-rest-api-v4 project (also in this repository). 31 | 32 | Blog post related to this project: N/A 33 | 34 | 35 | - spring-rest-api-v4: This project is the result of taking spring-rest-api-v32 (also in this repository) and upgrading it to version 4.0.0.RELEASE. It also contains some of the improvements included in this version of Spring, as commented in the blog entry. 36 | 37 | Blog post related to this project: 38 | http://xpadro.com/2014/01/migrating-spring-mvc-restful-web.html 39 | -------------------------------------------------------------------------------- /async-processing/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 4.0.0 5 | xpadro.spring.web 6 | async-processing 7 | war 8 | 1.0-SNAPSHOT 9 | async-processing Maven Webapp 10 | http://maven.apache.org 11 | 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 1.2.4.RELEASE 16 | 17 | 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-web 22 | 23 | 24 | org.springframework.boot 25 | spring-boot-starter-actuator 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-test 30 | test 31 | 32 | 33 | 34 | 35 | 1.8 36 | 37 | 38 | 39 | 40 | 41 | org.springframework.boot 42 | spring-boot-maven-plugin 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /async-processing/src/main/java/xpadro/spring/web/MainApp.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MainApp { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MainApp.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /async-processing/src/main/java/xpadro/spring/web/controller/AsyncCallableController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.controller; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import xpadro.spring.web.service.TaskService; 10 | 11 | import java.util.concurrent.Callable; 12 | 13 | @RestController 14 | public class AsyncCallableController { 15 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 16 | private final TaskService taskService; 17 | 18 | @Autowired 19 | public AsyncCallableController(TaskService taskService) { 20 | this.taskService = taskService; 21 | } 22 | 23 | @RequestMapping(value = "/callable", method = RequestMethod.GET, produces = "text/html") 24 | public Callable executeSlowTask() { 25 | logger.info("Request received"); 26 | Callable callable = taskService::execute; 27 | logger.info("Servlet thread released"); 28 | 29 | return callable; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /async-processing/src/main/java/xpadro/spring/web/controller/AsyncDeferredController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.controller; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import org.springframework.web.context.request.async.DeferredResult; 10 | import xpadro.spring.web.service.TaskService; 11 | 12 | import java.util.concurrent.CompletableFuture; 13 | 14 | @RestController 15 | public class AsyncDeferredController { 16 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 17 | private final TaskService taskService; 18 | 19 | @Autowired 20 | public AsyncDeferredController(TaskService taskService) { 21 | this.taskService = taskService; 22 | } 23 | 24 | @RequestMapping(value = "/deferred", method = RequestMethod.GET, produces = "text/html") 25 | public DeferredResult executeSlowTask() { 26 | logger.info("Request received"); 27 | DeferredResult deferredResult = new DeferredResult<>(); 28 | CompletableFuture.supplyAsync(taskService::execute) 29 | .whenCompleteAsync((result, throwable) -> deferredResult.setResult(result)); 30 | logger.info("Servlet thread released"); 31 | 32 | return deferredResult; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /async-processing/src/main/java/xpadro/spring/web/controller/BlockingController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.controller; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import xpadro.spring.web.service.TaskService; 10 | 11 | @RestController 12 | public class BlockingController { 13 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 14 | private final TaskService taskService; 15 | 16 | @Autowired 17 | public BlockingController(TaskService taskService) { 18 | this.taskService = taskService; 19 | } 20 | 21 | @RequestMapping(value = "/block", method = RequestMethod.GET, produces = "text/html") 22 | public String executeSlowTask() { 23 | logger.info("Request received"); 24 | String result = taskService.execute(); 25 | logger.info("Servlet thread released"); 26 | 27 | return result; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /async-processing/src/main/java/xpadro/spring/web/service/TaskService.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.service; 2 | 3 | public interface TaskService { 4 | 5 | String execute(); 6 | } 7 | -------------------------------------------------------------------------------- /async-processing/src/main/java/xpadro/spring/web/service/TaskServiceImpl.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.service; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public class TaskServiceImpl implements TaskService { 9 | private final Logger logger = LoggerFactory.getLogger(this.getClass()); 10 | 11 | @Override 12 | public String execute() { 13 | try { 14 | Thread.sleep(5000); 15 | logger.info("Slow task executed"); 16 | return "Task finished"; 17 | } catch (InterruptedException e) { 18 | throw new RuntimeException(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /async-processing/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Asynchronous Processing with Spring 7 | 8 | -------------------------------------------------------------------------------- /rest-controlleradvice/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /rest-controlleradvice/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /rest-controlleradvice/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | rest-controlleradvice 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | org.springframework.ide.eclipse.core.springbuilder 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.ide.eclipse.core.springnature 41 | org.eclipse.jem.workbench.JavaEMFNature 42 | org.eclipse.wst.common.modulecore.ModuleCoreNature 43 | org.eclipse.jdt.core.javanature 44 | org.eclipse.m2e.core.maven2Nature 45 | org.eclipse.wst.common.project.facet.core.nature 46 | org.eclipse.wst.jsdt.core.jsNature 47 | 48 | 49 | -------------------------------------------------------------------------------- /rest-controlleradvice/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /rest-controlleradvice/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.6 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 12 | org.eclipse.jdt.core.compiler.source=1.6 13 | -------------------------------------------------------------------------------- /rest-controlleradvice/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /rest-controlleradvice/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /rest-controlleradvice/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /rest-controlleradvice/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /rest-controlleradvice/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /rest-controlleradvice/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | xpadro.spring.rest 5 | rest-controlleradvice 6 | war 7 | 0.0.1-SNAPSHOT 8 | rest-controlleradvice Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | 3.2.1.RELEASE 13 | 2.5 14 | 1.2 15 | 1.2.14 16 | 4.8.1 17 | 1.4.2 18 | 4.3.1.Final 19 | 20 | 21 | 22 | 23 | 24 | org.springframework 25 | spring-context 26 | ${spring.version} 27 | 28 | 29 | org.springframework 30 | spring-webmvc 31 | ${spring.version} 32 | 33 | 34 | org.springframework 35 | spring-web 36 | ${spring.version} 37 | 38 | 39 | 40 | 41 | javax.servlet 42 | servlet-api 43 | ${servlet.version} 44 | provided 45 | 46 | 47 | javax.servlet 48 | jstl 49 | ${jstl.version} 50 | 51 | 52 | 53 | 54 | log4j 55 | log4j 56 | ${log4j.version} 57 | 58 | 59 | 60 | 61 | org.springframework 62 | spring-test 63 | ${spring.version} 64 | 65 | 66 | junit 67 | junit 68 | ${junit.version} 69 | 70 | 71 | 72 | 73 | org.codehaus.jackson 74 | jackson-mapper-asl 75 | 1.4.2 76 | 77 | 78 | 79 | org.hibernate 80 | hibernate-validator 81 | ${hibernate.version} 82 | 83 | 84 | 85 | 86 | rest-controlleradvice 87 | 88 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/controller/AddPersonController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.controller; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | import javax.validation.Valid; 6 | 7 | import org.apache.log4j.Logger; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | 16 | import xpadro.spring.rest.model.Person; 17 | import xpadro.spring.rest.repository.PersonRepository; 18 | 19 | /** 20 | * Adds a new person 21 | * @author xpadro 22 | * 23 | */ 24 | @Controller 25 | public class AddPersonController { 26 | private static Logger logger = Logger.getLogger("main"); 27 | 28 | @Autowired 29 | private PersonRepository personRepository; 30 | 31 | /** 32 | * CREATE operation. Adds a new person 33 | * @param person 34 | * @param request 35 | * @param response 36 | */ 37 | @RequestMapping(value="/persons", method=RequestMethod.POST) 38 | @ResponseStatus(HttpStatus.CREATED) 39 | public void addPerson(@Valid @RequestBody Person person, HttpServletRequest request, HttpServletResponse response) { 40 | personRepository.addPerson(person); 41 | logger.info("Person added: "+person.getId()); 42 | response.setHeader("Location", request.getRequestURL().append("/").append(person.getId()).toString()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/controller/GetPersonController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.controller; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.PathVariable; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.ResponseBody; 9 | 10 | import xpadro.spring.rest.model.Person; 11 | import xpadro.spring.rest.repository.PersonRepository; 12 | 13 | /** 14 | * Returns an existing person 15 | * @author xpadro 16 | * 17 | */ 18 | @Controller 19 | public class GetPersonController { 20 | @Autowired 21 | private PersonRepository personRepository; 22 | 23 | /** 24 | * READ operation. Returns an existing person 25 | * @param id 26 | * @return 27 | */ 28 | @RequestMapping(value="/persons/{personId}", method=RequestMethod.GET) 29 | public @ResponseBody Person getPerson(@PathVariable("personId") long id) { 30 | return personRepository.getPerson(id); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/controller/UpdatePersonController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.controller; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | import javax.validation.Valid; 6 | 7 | import org.apache.log4j.Logger; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.http.HttpStatus; 10 | import org.springframework.stereotype.Controller; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | 16 | import xpadro.spring.rest.model.Person; 17 | import xpadro.spring.rest.repository.PersonRepository; 18 | 19 | /** 20 | * Modifies an existing person 21 | * @author xpadro 22 | * 23 | */ 24 | @Controller 25 | public class UpdatePersonController { 26 | private static Logger logger = Logger.getLogger("main"); 27 | 28 | @Autowired 29 | private PersonRepository personRepository; 30 | 31 | /** 32 | * UPDATE operation. Modifies an existing person 33 | * @param person 34 | * @param request 35 | * @param response 36 | */ 37 | @RequestMapping(value="/persons", method=RequestMethod.PUT) 38 | @ResponseStatus(HttpStatus.CREATED) 39 | public void updatePerson(@Valid @RequestBody Person person, HttpServletRequest request, HttpServletResponse response) { 40 | personRepository.updatePerson(person); 41 | logger.info("Person updated: "+person.getId()); 42 | response.setHeader("Location", request.getRequestURL().append("/").append(person.getId()).toString()); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/controller/advice/CentralControllerHandler.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.controller.advice; 2 | 3 | import org.springframework.http.HttpStatus; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.web.bind.MethodArgumentNotValidException; 6 | import org.springframework.web.bind.WebDataBinder; 7 | import org.springframework.web.bind.annotation.ControllerAdvice; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.InitBinder; 10 | 11 | import xpadro.spring.rest.exception.PersonNotFoundException; 12 | import xpadro.spring.rest.validator.PersonValidator; 13 | 14 | @ControllerAdvice 15 | public class CentralControllerHandler { 16 | 17 | @InitBinder 18 | public void initBinder(WebDataBinder binder) { 19 | binder.setValidator(new PersonValidator()); 20 | } 21 | 22 | @ExceptionHandler({PersonNotFoundException.class}) 23 | public ResponseEntity handlePersonNotFound(PersonNotFoundException pe) { 24 | return new ResponseEntity(pe.getMessage(), HttpStatus.NOT_FOUND); 25 | } 26 | 27 | @ExceptionHandler({MethodArgumentNotValidException.class}) 28 | public ResponseEntity handleValidationException(MethodArgumentNotValidException pe) { 29 | return new ResponseEntity(pe.getMessage(), HttpStatus.BAD_REQUEST); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/exception/PersonNotFoundException.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.exception; 2 | 3 | /** 4 | * Exception to be thrown when trying to get a non existent person 5 | * @author xpadro 6 | * 7 | */ 8 | public class PersonNotFoundException extends RuntimeException { 9 | private static final long serialVersionUID = -3845574518872003019L; 10 | 11 | public PersonNotFoundException() { 12 | super(); 13 | } 14 | 15 | public PersonNotFoundException(String message) { 16 | super(message); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/model/Person.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.model; 2 | 3 | 4 | public class Person { 5 | 6 | private long id; 7 | private String name; 8 | private String surname; 9 | private String city; 10 | 11 | public Person() {} 12 | 13 | public Person(long id, String name, String surname, String city) { 14 | this.id = id; 15 | this.name = name; 16 | this.surname = surname; 17 | this.city = city; 18 | } 19 | 20 | 21 | /** 22 | * @return the id 23 | */ 24 | public long getId() { 25 | return id; 26 | } 27 | 28 | /** 29 | * @param id the id to set 30 | */ 31 | public void setId(long id) { 32 | this.id = id; 33 | } 34 | 35 | /** 36 | * @return the name 37 | */ 38 | public String getName() { 39 | return name; 40 | } 41 | 42 | /** 43 | * @param name the name to set 44 | */ 45 | public void setName(String name) { 46 | this.name = name; 47 | } 48 | 49 | /** 50 | * @return the surname 51 | */ 52 | public String getSurname() { 53 | return surname; 54 | } 55 | 56 | /** 57 | * @param surname the surname to set 58 | */ 59 | public void setSurname(String surname) { 60 | this.surname = surname; 61 | } 62 | 63 | /** 64 | * @return the city 65 | */ 66 | public String getCity() { 67 | return city; 68 | } 69 | 70 | /** 71 | * @param city the city to set 72 | */ 73 | public void setCity(String city) { 74 | this.city = city; 75 | } 76 | 77 | /* (non-Javadoc) 78 | * @see java.lang.Object#hashCode() 79 | */ 80 | @Override 81 | public int hashCode() { 82 | final int prime = 31; 83 | int result = 1; 84 | result = prime * result + ((city == null) ? 0 : city.hashCode()); 85 | result = prime * result + (int) (id ^ (id >>> 32)); 86 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 87 | result = prime * result + ((surname == null) ? 0 : surname.hashCode()); 88 | return result; 89 | } 90 | 91 | /* (non-Javadoc) 92 | * @see java.lang.Object#equals(java.lang.Object) 93 | */ 94 | @Override 95 | public boolean equals(Object obj) { 96 | if (this == obj) 97 | return true; 98 | if (obj == null) 99 | return false; 100 | if (getClass() != obj.getClass()) 101 | return false; 102 | Person other = (Person) obj; 103 | if (city == null) { 104 | if (other.city != null) 105 | return false; 106 | } else if (!city.equals(other.city)) 107 | return false; 108 | if (id != other.id) 109 | return false; 110 | if (name == null) { 111 | if (other.name != null) 112 | return false; 113 | } else if (!name.equals(other.name)) 114 | return false; 115 | if (surname == null) { 116 | if (other.surname != null) 117 | return false; 118 | } else if (!surname.equals(other.surname)) 119 | return false; 120 | return true; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/repository/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.repository; 2 | 3 | import xpadro.spring.rest.exception.PersonNotFoundException; 4 | import xpadro.spring.rest.model.Person; 5 | 6 | /** 7 | * Manages data from persons 8 | * @author xpadro 9 | * 10 | */ 11 | public interface PersonRepository { 12 | 13 | /** 14 | * Returns the person identified by the id 15 | * @param id 16 | * @return the person 17 | * @throws PersonNotFoundException if no person is found with specified id 18 | */ 19 | public Person getPerson(long id); 20 | 21 | /** 22 | * Adds a new person 23 | * @param person 24 | */ 25 | public void addPerson(Person person); 26 | 27 | /** 28 | * Modifies an existing person 29 | * @param person 30 | * @throws PersonNotFoundException if no person is found with specified id 31 | */ 32 | public void updatePerson(Person person); 33 | } 34 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/repository/impl/PersonRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.repository.impl; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import org.springframework.stereotype.Repository; 7 | 8 | import xpadro.spring.rest.exception.PersonNotFoundException; 9 | import xpadro.spring.rest.model.Person; 10 | import xpadro.spring.rest.repository.PersonRepository; 11 | 12 | @Repository 13 | public class PersonRepositoryImpl implements PersonRepository { 14 | private Map persons; 15 | 16 | public PersonRepositoryImpl() { 17 | persons = new HashMap(); 18 | createDummyPersons(); 19 | } 20 | 21 | @Override 22 | public Person getPerson(long id) { 23 | Person person = persons.get(id); 24 | if (person == null) { 25 | throw new PersonNotFoundException("No person found with id "+id); 26 | } 27 | 28 | return person; 29 | } 30 | 31 | @Override 32 | public void addPerson(Person person) { 33 | persons.put(person.getId(), person); 34 | } 35 | 36 | private void createDummyPersons() { 37 | Person person = new Person(1, "Xavi", "Padro", "Barcelona"); 38 | persons.put(1l, person); 39 | } 40 | 41 | @Override 42 | public void updatePerson(Person person) { 43 | if (persons.get(person.getId()) == null) { 44 | throw new PersonNotFoundException("No person found with id "+person.getId()); 45 | } 46 | persons.put(person.getId(), person); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/java/xpadro/spring/rest/validator/PersonValidator.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.validator; 2 | 3 | import org.springframework.validation.Errors; 4 | import org.springframework.validation.ValidationUtils; 5 | import org.springframework.validation.Validator; 6 | 7 | import xpadro.spring.rest.model.Person; 8 | 9 | /** 10 | * Validates that a person is from a registered city 11 | * @author xpadro 12 | * 13 | */ 14 | public class PersonValidator implements Validator { 15 | 16 | public boolean supports(Class clazz) { 17 | return clazz.equals(Person.class); 18 | } 19 | 20 | public void validate(Object target, Errors errors) { 21 | Person person = (Person) target; 22 | 23 | ValidationUtils.rejectIfEmpty(errors, "city", "city.empty"); 24 | if (!"Barcelona".equals(person.getCity()) && !"Liverpool".equals(person.getCity())) { 25 | errors.rejectValue("city", "city.not.valid", "Invalid city: "+person.getCity()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/resources/xpadro/spring/rest/configuration/app-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/resources/xpadro/spring/rest/configuration/root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SpringRestControllerAdvice 4 | 5 | 6 | 7 | contextConfigLocation 8 | classpath:xpadro/spring/rest/configuration/root-context.xml 9 | 10 | 11 | 12 | 13 | org.springframework.web.context.ContextLoaderListener 14 | 15 | 16 | 17 | 18 | springServlet 19 | org.springframework.web.servlet.DispatcherServlet 20 | 21 | contextConfigLocation 22 | classpath:xpadro/spring/rest/configuration/app-context.xml 23 | 24 | 25 | 26 | springServlet 27 | /spring/* 28 | 29 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

@ControllerAdvice sample

4 | 5 | 6 | -------------------------------------------------------------------------------- /rest-controlleradvice/src/test/java/xpadro/spring/rest/client/PersonRestServiceTesting.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.client; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.net.URI; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 13 | import org.springframework.web.client.HttpClientErrorException; 14 | import org.springframework.web.client.RestTemplate; 15 | 16 | import xpadro.spring.rest.model.Person; 17 | 18 | @RunWith(SpringJUnit4ClassRunner.class) 19 | @ContextConfiguration(locations={ 20 | "classpath:xpadro/spring/rest/configuration/root-context.xml", 21 | "classpath:xpadro/spring/rest/configuration/app-context.xml"}) 22 | public class PersonRestServiceTesting { 23 | private RestTemplate restTemplate = new RestTemplate(); 24 | 25 | 26 | /** 27 | * Tests retrieving an existing person 28 | */ 29 | @Test 30 | public void getExistingPerson() { 31 | String uri = "http://localhost:8081/rest-controlleradvice/spring/persons/{personId}"; 32 | Person person = restTemplate.getForObject(uri, Person.class, 1l); 33 | assertNotNull(person); 34 | assertEquals("Xavi", person.getName()); 35 | } 36 | 37 | /** 38 | * Tests error handling when trying to retrieve a non existent person 39 | */ 40 | @Test 41 | public void getNonExistingPerson() { 42 | String uri = "http://localhost:8081/rest-controlleradvice/spring/persons/{personId}"; 43 | try { 44 | restTemplate.getForObject(uri, Person.class, 5l); 45 | throw new AssertionError("Should have returned an 404 error code"); 46 | } catch (HttpClientErrorException e) { 47 | assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode()); 48 | } 49 | } 50 | 51 | /** 52 | * Tests the addition of a new person 53 | */ 54 | @Test 55 | public void addValidPerson() { 56 | String uri = "http://localhost:8081/rest-controlleradvice/spring/persons"; 57 | Person person = new Person(2l, "John", "Lennon", "Liverpool"); 58 | URI newPersonLocation = restTemplate.postForLocation(uri, person, 2l); 59 | 60 | Person createdPerson = restTemplate.getForObject(newPersonLocation, Person.class); 61 | assertEquals(person, createdPerson); 62 | assertNotNull(createdPerson.getId()); 63 | assertEquals("John", person.getName()); 64 | } 65 | 66 | /** 67 | * Tests error handling when trying to add a person with invalid data 68 | */ 69 | @Test 70 | public void addInvalidPerson() { 71 | String uri = "http://localhost:8081/rest-controlleradvice/spring/persons"; 72 | Person person = new Person(3l, "James", "Steward", "London"); 73 | try { 74 | restTemplate.postForLocation(uri, person, 3l); 75 | throw new AssertionError("Should have returned an 400 error code"); 76 | } catch (HttpClientErrorException e) { 77 | assertEquals(HttpStatus.BAD_REQUEST, e.getStatusCode()); 78 | } 79 | } 80 | 81 | /** 82 | * Tests updating an existing person 83 | */ 84 | @Test 85 | public void updateValidPerson() { 86 | String uri = "http://localhost:8081/rest-controlleradvice/spring/persons"; 87 | Person person = new Person(2l, "George", "Harrison", "Liverpool"); 88 | restTemplate.put(uri, person, 2l); 89 | 90 | uri = "http://localhost:8081/rest-controlleradvice/spring/persons/{personId}"; 91 | Person createdPerson = restTemplate.getForObject(uri, Person.class, 2l); 92 | assertEquals(person, createdPerson); 93 | assertNotNull(createdPerson.getId()); 94 | assertEquals("George", person.getName()); 95 | } 96 | 97 | /** 98 | * Tests error handling when trying to update an existing person with invalid data 99 | */ 100 | @Test 101 | public void updateInvalidPerson() { 102 | String uri = "http://localhost:8081/rest-controlleradvice/spring/persons"; 103 | Person person = new Person(2l, "John", "Smith", "New York"); 104 | try { 105 | restTemplate.put(uri, person, 2l); 106 | throw new AssertionError("Should have returned an 400 error code"); 107 | } catch (HttpClientErrorException e) { 108 | assertEquals(HttpStatus.BAD_REQUEST, e.getStatusCode()); 109 | } 110 | } 111 | 112 | /** 113 | * Tests error handling when trying to update a non existing person 114 | */ 115 | @Test 116 | public void updateNonExistingPerson() { 117 | String uri = "http://localhost:8081/rest-controlleradvice/spring/persons"; 118 | Person person = new Person(5l, "Marc", "Brown", "Barcelona"); 119 | try { 120 | restTemplate.put(uri, person, 5l); 121 | throw new AssertionError("Should have returned an 404 error code"); 122 | } catch (HttpClientErrorException e) { 123 | assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode()); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /rest-converters/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /rest-converters/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /rest-converters/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | rest-converters 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | org.springframework.ide.eclipse.core.springbuilder 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.ide.eclipse.core.springnature 41 | org.eclipse.jem.workbench.JavaEMFNature 42 | org.eclipse.wst.common.modulecore.ModuleCoreNature 43 | org.eclipse.jdt.core.javanature 44 | org.eclipse.m2e.core.maven2Nature 45 | org.eclipse.wst.common.project.facet.core.nature 46 | org.eclipse.wst.jsdt.core.jsNature 47 | 48 | 49 | -------------------------------------------------------------------------------- /rest-converters/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /rest-converters/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.compliance=1.6 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.6 9 | -------------------------------------------------------------------------------- /rest-converters/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /rest-converters/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /rest-converters/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /rest-converters/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /rest-converters/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /rest-converters/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | xpadro.spring.rest 5 | rest-converters 6 | war 7 | 0.0.1-SNAPSHOT 8 | rest-converters Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | 3.2.1.RELEASE 13 | 1.3.3.RELEASE 14 | 2.5 15 | 1.2 16 | 1.2.14 17 | 4.8.1 18 | 1.4.2 19 | 20 | 21 | 22 | 23 | 24 | org.springframework 25 | spring-context 26 | ${spring.version} 27 | 28 | 29 | org.springframework 30 | spring-webmvc 31 | ${spring.version} 32 | 33 | 34 | org.springframework 35 | spring-web 36 | ${spring.version} 37 | 38 | 39 | 40 | 41 | org.springframework.data 42 | spring-data-mongodb 43 | ${spring.mongo.version} 44 | 45 | 46 | 47 | 48 | 49 | javax.servlet 50 | servlet-api 51 | ${servlet.version} 52 | provided 53 | 54 | 55 | javax.servlet 56 | jstl 57 | ${jstl.version} 58 | 59 | 60 | 61 | 62 | log4j 63 | log4j 64 | ${log4j.version} 65 | 66 | 67 | 68 | 69 | org.springframework 70 | spring-test 71 | ${spring.version} 72 | 73 | 74 | junit 75 | junit 76 | ${junit.version} 77 | 78 | 79 | 80 | 81 | org.codehaus.jackson 82 | jackson-mapper-asl 83 | 1.4.2 84 | 85 | 86 | 87 | rest-converters 88 | 89 | -------------------------------------------------------------------------------- /rest-converters/src/main/java/xpadro/spring/rest/controller/MvcRestController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.controller; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.stereotype.Controller; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestMethod; 13 | import org.springframework.web.bind.annotation.ResponseBody; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | 16 | import xpadro.spring.rest.model.Car; 17 | import xpadro.spring.rest.model.User; 18 | import xpadro.spring.rest.repository.CarRepository; 19 | import xpadro.spring.rest.repository.UserRepository; 20 | 21 | @Controller 22 | public class MvcRestController { 23 | @Autowired 24 | private UserRepository userRepository; 25 | 26 | @Autowired 27 | private CarRepository carRepository; 28 | 29 | 30 | /** 31 | * Returns the requested user by its id. 32 | * The response will be converted to JSON 33 | * @param id 34 | * @return The requested user 35 | */ 36 | @RequestMapping(value="/users/{userId}", method=RequestMethod.GET) 37 | public @ResponseBody User getUser(@PathVariable("userId") long id) { 38 | return userRepository.getUser(id); 39 | } 40 | 41 | 42 | /** 43 | * Returns the name of the requested user. 44 | * The response will be converted to String 45 | * @param id 46 | * @return 47 | */ 48 | @RequestMapping(value="/usernames/{userId}", method=RequestMethod.GET) 49 | public @ResponseBody String getUsername(@PathVariable("userId") long id) { 50 | StringBuilder result = new StringBuilder(); 51 | User user = userRepository.getUser(id); 52 | return result.append(user.getName()).append(" ").append(user.getSurname()).toString(); 53 | } 54 | 55 | /** 56 | * Returns the requested car by its id. 57 | * The response will be converted to XML 58 | * @param id 59 | * @return 60 | */ 61 | @RequestMapping(value="/cars/{carId}", method=RequestMethod.GET) 62 | public @ResponseBody Car getCar(@PathVariable("carId") long id) { 63 | return carRepository.getCar(id); 64 | } 65 | 66 | /** 67 | * Inserts a new user to the DB 68 | * @param user 69 | * @param request 70 | * @param response 71 | */ 72 | @RequestMapping(value="/users", method=RequestMethod.POST) 73 | @ResponseStatus(HttpStatus.CREATED) 74 | public void insertUser(@RequestBody User user, HttpServletRequest request, HttpServletResponse response) { 75 | userRepository.insertUser(user); 76 | response.setHeader("Location", request.getRequestURL().append("/").append(user.getId()).toString()); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /rest-converters/src/main/java/xpadro/spring/rest/model/Car.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.xml.bind.annotation.XmlElement; 6 | import javax.xml.bind.annotation.XmlRootElement; 7 | 8 | @XmlRootElement(name="car") 9 | public class Car implements Serializable { 10 | private static final long serialVersionUID = -4143762939567940616L; 11 | private long id; 12 | private String brand; 13 | private String model; 14 | 15 | public Car() { } 16 | 17 | public Car(long id, String brand, String model) { 18 | this.id = id; 19 | this.brand = brand; 20 | this.model = model; 21 | } 22 | 23 | @XmlElement 24 | public long getId() { 25 | return id; 26 | } 27 | 28 | public void setId(long id) { 29 | this.id = id; 30 | } 31 | 32 | @XmlElement 33 | public String getBrand() { 34 | return brand; 35 | } 36 | 37 | public void setBrand(String brand) { 38 | this.brand = brand; 39 | } 40 | 41 | @XmlElement 42 | public String getModel() { 43 | return model; 44 | } 45 | 46 | public void setModel(String model) { 47 | this.model = model; 48 | } 49 | } -------------------------------------------------------------------------------- /rest-converters/src/main/java/xpadro/spring/rest/model/User.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class User implements Serializable { 6 | 7 | private static final long serialVersionUID = -149936843837396000L; 8 | private long id; 9 | private String name; 10 | private String surname; 11 | 12 | public User() {} 13 | 14 | public User(long id, String name, String surname) { 15 | this.id = id; 16 | this.name = name; 17 | this.surname = surname; 18 | } 19 | 20 | /** 21 | * @return the id 22 | */ 23 | public long getId() { 24 | return id; 25 | } 26 | /** 27 | * @param id the id to set 28 | */ 29 | public void setId(long id) { 30 | this.id = id; 31 | } 32 | /** 33 | * @return the name 34 | */ 35 | public String getName() { 36 | return name; 37 | } 38 | /** 39 | * @param name the name to set 40 | */ 41 | public void setName(String name) { 42 | this.name = name; 43 | } 44 | /** 45 | * @return the surname 46 | */ 47 | public String getSurname() { 48 | return surname; 49 | } 50 | /** 51 | * @param surname the surname to set 52 | */ 53 | public void setSurname(String surname) { 54 | this.surname = surname; 55 | } 56 | 57 | /* (non-Javadoc) 58 | * @see java.lang.Object#hashCode() 59 | */ 60 | @Override 61 | public int hashCode() { 62 | final int prime = 31; 63 | int result = 1; 64 | result = prime * result + (int) (id ^ (id >>> 32)); 65 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 66 | result = prime * result + ((surname == null) ? 0 : surname.hashCode()); 67 | return result; 68 | } 69 | 70 | /* (non-Javadoc) 71 | * @see java.lang.Object#equals(java.lang.Object) 72 | */ 73 | @Override 74 | public boolean equals(Object obj) { 75 | if (this == obj) 76 | return true; 77 | if (obj == null) 78 | return false; 79 | if (getClass() != obj.getClass()) 80 | return false; 81 | User other = (User) obj; 82 | if (id != other.id) 83 | return false; 84 | if (name == null) { 85 | if (other.name != null) 86 | return false; 87 | } else if (!name.equals(other.name)) 88 | return false; 89 | if (surname == null) { 90 | if (other.surname != null) 91 | return false; 92 | } else if (!surname.equals(other.surname)) 93 | return false; 94 | return true; 95 | } 96 | 97 | /* (non-Javadoc) 98 | * @see java.lang.Object#toString() 99 | */ 100 | @Override 101 | public String toString() { 102 | return "User [id=" + id + ", name=" + name + ", surname=" + surname 103 | + "]"; 104 | } 105 | } -------------------------------------------------------------------------------- /rest-converters/src/main/java/xpadro/spring/rest/repository/CarRepository.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.repository; 2 | 3 | import xpadro.spring.rest.model.Car; 4 | 5 | 6 | /** 7 | * Manages data from cars 8 | * @author xpadro 9 | * 10 | */ 11 | public interface CarRepository { 12 | 13 | /** 14 | * Returns the car identified by the id 15 | * @param id 16 | * @return the car 17 | */ 18 | public Car getCar(long id); 19 | } 20 | -------------------------------------------------------------------------------- /rest-converters/src/main/java/xpadro/spring/rest/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.repository; 2 | 3 | import xpadro.spring.rest.model.User; 4 | 5 | /** 6 | * Manages data from users 7 | * @author xpadro 8 | * 9 | */ 10 | public interface UserRepository { 11 | 12 | /** 13 | * Returns the user identified by the id 14 | * @param id 15 | * @return the user 16 | */ 17 | public User getUser(long id); 18 | 19 | /** 20 | * Inserts a user into the DB 21 | * @param user 22 | */ 23 | public void insertUser(User user); 24 | } 25 | -------------------------------------------------------------------------------- /rest-converters/src/main/java/xpadro/spring/rest/repository/impl/CarRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.repository.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.data.mongodb.core.MongoOperations; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import xpadro.spring.rest.model.Car; 8 | import xpadro.spring.rest.repository.CarRepository; 9 | 10 | @Repository 11 | public class CarRepositoryImpl implements CarRepository { 12 | @Autowired 13 | private MongoOperations mongoOps; 14 | 15 | @Override 16 | public Car getCar(long id) { 17 | return mongoOps.findById(1, Car.class); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /rest-converters/src/main/java/xpadro/spring/rest/repository/impl/UserRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.repository.impl; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.data.mongodb.core.MongoOperations; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import xpadro.spring.rest.model.User; 8 | import xpadro.spring.rest.repository.UserRepository; 9 | 10 | @Repository 11 | public class UserRepositoryImpl implements UserRepository { 12 | @Autowired 13 | private MongoOperations mongoOps; 14 | 15 | @Override 16 | public User getUser(long id) { 17 | return mongoOps.findById(id, User.class); 18 | } 19 | 20 | @Override 21 | public void insertUser(User user) { 22 | mongoOps.insert(user); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /rest-converters/src/main/resources/xpadro/spring/rest/configuration/app-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /rest-converters/src/main/resources/xpadro/spring/rest/configuration/db-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /rest-converters/src/main/resources/xpadro/spring/rest/configuration/root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /rest-converters/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SpringRestConverters 4 | 5 | 6 | 7 | contextConfigLocation 8 | classpath:xpadro/spring/rest/configuration/root-context.xml 9 | 10 | 11 | 12 | 13 | org.springframework.web.context.ContextLoaderListener 14 | 15 | 16 | 17 | 18 | springServlet 19 | org.springframework.web.servlet.DispatcherServlet 20 | 21 | contextConfigLocation 22 | classpath:xpadro/spring/rest/configuration/app-context.xml 23 | 24 | 25 | 26 | springServlet 27 | /spring/* 28 | 29 | -------------------------------------------------------------------------------- /rest-converters/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | -------------------------------------------------------------------------------- /rest-converters/src/test/java/xpadro/spring/rest/client/RestTesting.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.rest.client; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.net.URI; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.junit.runner.RunWith; 13 | import org.springframework.beans.factory.annotation.Autowired; 14 | import org.springframework.data.mongodb.core.MongoOperations; 15 | import org.springframework.http.converter.HttpMessageConverter; 16 | import org.springframework.http.converter.StringHttpMessageConverter; 17 | import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; 18 | import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; 19 | import org.springframework.test.context.ContextConfiguration; 20 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 21 | import org.springframework.web.client.RestTemplate; 22 | 23 | import xpadro.spring.rest.model.Car; 24 | import xpadro.spring.rest.model.User; 25 | 26 | @RunWith(SpringJUnit4ClassRunner.class) 27 | @ContextConfiguration(locations={ 28 | "classpath:xpadro/spring/rest/configuration/root-context.xml", 29 | "classpath:xpadro/spring/rest/configuration/app-context.xml"}) 30 | public class RestTesting { 31 | private static final String BASE_URI = "http://localhost:8080/rest-converters/spring/"; 32 | private RestTemplate restTemplate = new RestTemplate(); 33 | 34 | @Autowired 35 | private MongoOperations mongoOps; 36 | 37 | @Before 38 | public void setup() { 39 | List> converters = new ArrayList>(); 40 | converters.add(new StringHttpMessageConverter()); 41 | converters.add(new Jaxb2RootElementHttpMessageConverter()); 42 | converters.add(new MappingJacksonHttpMessageConverter()); 43 | restTemplate.setMessageConverters(converters); 44 | 45 | initializeDatabase(); 46 | } 47 | 48 | private void initializeDatabase() { 49 | mongoOps.dropCollection("user"); 50 | mongoOps.dropCollection("car"); 51 | 52 | mongoOps.insert(new User(1, "Xavi", "Padro")); 53 | mongoOps.insert(new Car(1, "Ferrari", "GTO")); 54 | } 55 | 56 | 57 | /** 58 | * Tests accessing to an existing user 59 | * This test should use the MappingJacksonHttpMessageConverter 60 | */ 61 | @Test 62 | public void getUser() { 63 | String uri = BASE_URI + "users/{userId}"; 64 | User user = restTemplate.getForObject(uri, User.class, 1l); 65 | assertNotNull(user); 66 | assertEquals("Xavi", user.getName()); 67 | } 68 | 69 | /** 70 | * Tests accessing to an existing user 71 | * This test should use the StringHttpMessageConverter 72 | */ 73 | @Test 74 | public void getUserName() { 75 | String uri = BASE_URI + "usernames/{userId}"; 76 | String username = restTemplate.getForObject(uri, String.class, 1l); 77 | assertNotNull(username); 78 | assertEquals("Xavi Padro", username); 79 | } 80 | 81 | /** 82 | * Tests accessing to an existing car 83 | * This test should use the Jaxb2RootElementHttpMessageConverter 84 | */ 85 | @Test 86 | public void getCar() { 87 | String uri = BASE_URI + "cars/{carId}"; 88 | Car car = restTemplate.getForObject(uri, Car.class, 1l); 89 | assertNotNull(car); 90 | assertEquals("Ferrari", car.getBrand()); 91 | } 92 | 93 | /** 94 | * Tests a new user insertion 95 | */ 96 | @Test 97 | public void insertUser() { 98 | String uri = BASE_URI + "users"; 99 | User user = new User(2, "John", "Smith"); 100 | URI newUserLocation = restTemplate.postForLocation(uri, user); 101 | assertEquals("http://localhost:8080/rest-converters/spring/users/2", newUserLocation.toString()); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /rest-subresources/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /rest-subresources/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /rest-subresources/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | rest-subresources 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | org.eclipse.wst.common.project.facet.core.nature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | 43 | -------------------------------------------------------------------------------- /rest-subresources/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /rest-subresources/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 4 | org.eclipse.jdt.core.compiler.compliance=1.5 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.5 9 | -------------------------------------------------------------------------------- /rest-subresources/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /rest-subresources/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /rest-subresources/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /rest-subresources/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /rest-subresources/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /rest-subresources/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | xpadro.rest.ri 5 | rest-subresources 6 | war 7 | 0.0.1-SNAPSHOT 8 | rest-subresources Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | 1.17.1 13 | 14 | 15 | 16 | 17 | com.sun.jersey 18 | jersey-server 19 | ${jersey.version} 20 | 21 | 22 | com.sun.jersey 23 | jersey-servlet 24 | ${jersey.version} 25 | 26 | 27 | com.sun.jersey 28 | jersey-json 29 | ${jersey.version} 30 | 31 | 32 | 33 | rest-subresources 34 | 35 | 36 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/model/Item.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Item implements Serializable { 6 | private static final long serialVersionUID = 1L; 7 | private int id; 8 | private float price; 9 | private String type; 10 | 11 | 12 | public Item() {} 13 | 14 | public Item(int id, float price, String type) { 15 | this.id = id; 16 | this.price = price; 17 | this.type = type; 18 | } 19 | 20 | 21 | /** 22 | * @return the id 23 | */ 24 | public int getId() { 25 | return id; 26 | } 27 | /** 28 | * @param id the id to set 29 | */ 30 | public void setId(int id) { 31 | this.id = id; 32 | } 33 | 34 | /** 35 | * @return the price 36 | */ 37 | public float getPrice() { 38 | return price; 39 | } 40 | 41 | /** 42 | * @param price the price to set 43 | */ 44 | public void setPrice(float price) { 45 | this.price = price; 46 | } 47 | 48 | /** 49 | * @return the type 50 | */ 51 | public String getType() { 52 | return type; 53 | } 54 | 55 | /** 56 | * @param type the type to set 57 | */ 58 | public void setType(String type) { 59 | this.type = type; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/model/TypeAItem.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.model; 2 | 3 | public class TypeAItem extends Item { 4 | private static final long serialVersionUID = 1L; 5 | private String code; 6 | 7 | public TypeAItem() {} 8 | 9 | public TypeAItem(int id, float price, String code) { 10 | super(id, price, "A"); 11 | this.code = code; 12 | } 13 | 14 | /** 15 | * @return the code 16 | */ 17 | public String getCode() { 18 | return code; 19 | } 20 | 21 | /** 22 | * @param code the code to set 23 | */ 24 | public void setCode(String code) { 25 | this.code = code; 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/model/TypeBItem.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.model; 2 | 3 | public class TypeBItem extends Item { 4 | private static final long serialVersionUID = 1L; 5 | 6 | public TypeBItem() {} 7 | 8 | public TypeBItem(int id, float price) { 9 | super(id, price, "B"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/repository/TypeAItemRepository.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.repository; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import xpadro.rest.ri.model.TypeAItem; 7 | 8 | public class TypeAItemRepository { 9 | private Map items; 10 | 11 | public TypeAItemRepository() { 12 | items = new HashMap(); 13 | items.put(11, new TypeAItem(11, 50.99f, "56FG84")); 14 | items.put(12, new TypeAItem(12, 35.50f, "12SS34")); 15 | items.put(13, new TypeAItem(13, 19.90f, "87HU75")); 16 | } 17 | 18 | public TypeAItem retrieveItem(int id) { 19 | return items.get(id); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/repository/TypeBItemRepository.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.repository; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import xpadro.rest.ri.model.TypeBItem; 7 | 8 | public class TypeBItemRepository { 9 | private Map items; 10 | 11 | public TypeBItemRepository() { 12 | items = new HashMap(); 13 | items.put(1, new TypeBItem(1, 33.50f)); 14 | items.put(2, new TypeBItem(2, 55.50f)); 15 | items.put(3, new TypeBItem(3, 95.99f)); 16 | } 17 | 18 | public TypeBItem retrieveItem(int id) { 19 | return items.get(id); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/resources/ItemResource.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.resources; 2 | 3 | public interface ItemResource { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/resources/TypeAResource.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.resources; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Produces; 5 | import javax.ws.rs.WebApplicationException; 6 | import javax.ws.rs.core.MediaType; 7 | import javax.ws.rs.core.Response; 8 | 9 | import xpadro.rest.ri.model.TypeAItem; 10 | import xpadro.rest.ri.repository.TypeAItemRepository; 11 | 12 | /** 13 | * Type A Subresource 14 | */ 15 | public class TypeAResource implements ItemResource { 16 | private int itemId; 17 | private TypeAItemRepository itemRepository = new TypeAItemRepository(); 18 | 19 | public TypeAResource(int id) { 20 | this.itemId = id; 21 | } 22 | 23 | @GET 24 | @Produces(MediaType.APPLICATION_JSON) 25 | public TypeAItem getTypeAItem() { 26 | TypeAItem item = itemRepository.retrieveItem(itemId); 27 | if (item == null) { 28 | throw new WebApplicationException(Response.Status.NOT_FOUND); 29 | } 30 | 31 | return item; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/resources/TypeBResource.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.resources; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Produces; 5 | import javax.ws.rs.WebApplicationException; 6 | import javax.ws.rs.core.MediaType; 7 | import javax.ws.rs.core.Response; 8 | 9 | import xpadro.rest.ri.model.TypeBItem; 10 | import xpadro.rest.ri.repository.TypeBItemRepository; 11 | 12 | /** 13 | * Type B Subresource 14 | */ 15 | public class TypeBResource implements ItemResource { 16 | private int itemId; 17 | private TypeBItemRepository itemRepository = new TypeBItemRepository(); 18 | 19 | public TypeBResource(int id) { 20 | this.itemId = id; 21 | } 22 | 23 | @GET 24 | @Produces(MediaType.APPLICATION_JSON) 25 | public TypeBItem getTypeBItem() { 26 | TypeBItem item = itemRepository.retrieveItem(itemId); 27 | if (item == null) { 28 | throw new WebApplicationException(Response.Status.NOT_FOUND); 29 | } 30 | 31 | return item; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rest-subresources/src/main/java/xpadro/rest/ri/resources/WarehouseResource.java: -------------------------------------------------------------------------------- 1 | package xpadro.rest.ri.resources; 2 | 3 | import javax.ws.rs.GET; 4 | import javax.ws.rs.Path; 5 | import javax.ws.rs.PathParam; 6 | 7 | /** 8 | * Root resource 9 | */ 10 | @Path("/warehouse") 11 | public class WarehouseResource { 12 | 13 | @GET 14 | public String getWarehouseInfo() { 15 | return "Warehouse location: Barcelona"; 16 | } 17 | 18 | @Path("/items/{itemId}") 19 | public ItemResource getItem(@PathParam("itemId") Integer itemId) { 20 | ItemResource itemResource = null; 21 | 22 | if (itemId > 10) { 23 | itemResource = new TypeAResource(itemId); 24 | } 25 | else { 26 | itemResource = new TypeBResource(itemId); 27 | } 28 | 29 | return itemResource; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /rest-subresources/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Archetype Created Web Application 7 | 8 | 9 | Jersey Servlet 10 | com.sun.jersey.spi.container.servlet.ServletContainer 11 | 12 | com.sun.jersey.config.property.packages 13 | xpadro.rest.ri.resources 14 | 15 | 16 | com.sun.jersey.api.json.POJOMappingFeature 17 | true 18 | 19 | 1 20 | 21 | 22 | 23 | Jersey Servlet 24 | /rest/* 25 | 26 | 27 | -------------------------------------------------------------------------------- /rest-subresources/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Hello World!

4 | 5 | 6 | -------------------------------------------------------------------------------- /rest_test/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /rest_test/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /rest_test/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | rest_test 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.wst.common.project.facet.core.builder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | org.eclipse.m2e.core.maven2Builder 25 | 26 | 27 | 28 | 29 | org.eclipse.wst.validation.validationbuilder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.jem.workbench.JavaEMFNature 36 | org.eclipse.wst.common.modulecore.ModuleCoreNature 37 | org.eclipse.jdt.core.javanature 38 | org.eclipse.m2e.core.maven2Nature 39 | org.eclipse.wst.common.project.facet.core.nature 40 | org.eclipse.wst.jsdt.core.jsNature 41 | 42 | 43 | -------------------------------------------------------------------------------- /rest_test/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /rest_test/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.compliance=1.6 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.6 9 | -------------------------------------------------------------------------------- /rest_test/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /rest_test/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /rest_test/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /rest_test/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /rest_test/.settings/org.maven.ide.eclipse.prefs: -------------------------------------------------------------------------------- 1 | #Sun Feb 03 11:31:23 CET 2013 2 | activeProfiles= 3 | eclipse.preferences.version=1 4 | fullBuildGoals=process-test-resources 5 | includeModules=false 6 | resolveWorkspaceProjects=true 7 | resourceFilterGoals=process-resources resources\:testResources 8 | skipCompilerPlugin=true 9 | version=1 10 | -------------------------------------------------------------------------------- /rest_test/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | xpadro.tutorial.rest 4 | rest_test 5 | 0.0.1-SNAPSHOT 6 | 7 | 8 | 3.2.1.RELEASE 9 | 2.5 10 | 1.2 11 | 1.2.14 12 | 4.8.1 13 | 1.4.2 14 | 15 | 16 | 17 | 18 | 19 | org.springframework 20 | spring-context 21 | ${spring.version} 22 | 23 | 24 | org.springframework 25 | spring-webmvc 26 | ${spring.version} 27 | 28 | 29 | org.springframework 30 | spring-web 31 | ${spring.version} 32 | 33 | 34 | 35 | 36 | javax.servlet 37 | servlet-api 38 | ${servlet.version} 39 | provided 40 | 41 | 42 | javax.servlet 43 | jstl 44 | ${jstl.version} 45 | 46 | 47 | 48 | 49 | log4j 50 | log4j 51 | ${log4j.version} 52 | 53 | 54 | 55 | 56 | org.springframework 57 | spring-test 58 | ${spring.version} 59 | 60 | 61 | junit 62 | junit 63 | ${junit.version} 64 | 65 | 66 | 67 | 68 | org.codehaus.jackson 69 | jackson-mapper-asl 70 | ${json.version} 71 | 72 | 73 | 74 | war 75 | -------------------------------------------------------------------------------- /rest_test/src/main/java/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /rest_test/src/main/java/xpadro/tutorial/rest/controller/WarehouseController.java: -------------------------------------------------------------------------------- 1 | package xpadro.tutorial.rest.controller; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.apache.log4j.Logger; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.WebDataBinder; 11 | import org.springframework.web.bind.annotation.ExceptionHandler; 12 | import org.springframework.web.bind.annotation.InitBinder; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.RequestBody; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RequestMethod; 17 | import org.springframework.web.bind.annotation.ResponseBody; 18 | import org.springframework.web.bind.annotation.ResponseStatus; 19 | import org.springframework.web.context.request.WebRequest; 20 | 21 | import xpadro.tutorial.rest.exception.ProductNotFoundException; 22 | import xpadro.tutorial.rest.model.Product; 23 | import xpadro.tutorial.rest.model.Warehouse; 24 | import xpadro.tutorial.rest.repository.WarehouseRepository; 25 | 26 | /** 27 | * Contains CRUD operations on warehouses and its products. 28 | * @author xpadro 29 | * 30 | */ 31 | @Controller 32 | public class WarehouseController { 33 | private static Logger logger = Logger.getLogger("main"); 34 | 35 | @Autowired 36 | private WarehouseRepository warehouseRepository; 37 | 38 | 39 | /** 40 | * Returns the warehouse requested by its id. 41 | * @param id 42 | * @return The requested warehouse 43 | */ 44 | @RequestMapping(value="/warehouses/{warehouseId}", method=RequestMethod.GET) 45 | public @ResponseBody Warehouse getWarehouse(@PathVariable("warehouseId") int id) { 46 | return warehouseRepository.getWarehouse(id); 47 | } 48 | 49 | /** 50 | * Adds a new product to the specified warehouse. 51 | * @param warehouseId The id of the warehouse where to add the new product 52 | * @param product The new product to be created 53 | * @param request 54 | * @param response 55 | */ 56 | @RequestMapping(value="/warehouses/{warehouseId}/products", method=RequestMethod.POST) 57 | @ResponseStatus(HttpStatus.CREATED) 58 | public void addProduct(@PathVariable("warehouseId") int warehouseId, @RequestBody Product product, 59 | HttpServletRequest request, HttpServletResponse response) { 60 | 61 | warehouseRepository.addProduct(warehouseId, product); 62 | response.setHeader("Location", request.getRequestURL().append("/").append(product.getId()).toString()); 63 | } 64 | 65 | /** 66 | * Removes a product from a specified warehouse. 67 | * @param warehouseId The id of the warehouse where to remove the product 68 | * @param productId The id of the product to be removed 69 | * @param request 70 | * @param response 71 | */ 72 | @RequestMapping(value="/warehouses/{warehouseId}/products/{productId}", method=RequestMethod.DELETE) 73 | @ResponseStatus(HttpStatus.NO_CONTENT) 74 | public void removeProduct(@PathVariable("warehouseId") int warehouseId, @PathVariable("productId") int productId, 75 | HttpServletRequest request, HttpServletResponse response) { 76 | 77 | warehouseRepository.removeProduct(warehouseId, productId); 78 | } 79 | 80 | /** 81 | * Returns the product from a specified warehouse. 82 | * @param warehouseId The id of the warehouse where to get the product 83 | * @param productId 84 | * @return 85 | */ 86 | @RequestMapping(value="/warehouses/{warehouseId}/products/{productId}", method=RequestMethod.GET) 87 | public @ResponseBody Product getProduct(@PathVariable("warehouseId") int warehouseId, @PathVariable("productId") int productId) { 88 | return warehouseRepository.getProduct(warehouseId, productId); 89 | } 90 | 91 | /** 92 | * Handles ProductNotFoundException and returns a 404 response status code 93 | */ 94 | @ResponseStatus(HttpStatus.NOT_FOUND) 95 | @ExceptionHandler({ProductNotFoundException.class}) 96 | public void handleProductNotFound(ProductNotFoundException pe) { 97 | logger.warn("Product not found. Code: "+pe.getMessage()); 98 | } 99 | 100 | 101 | @InitBinder 102 | public void testBinder(WebDataBinder binder, WebRequest req) { 103 | System.out.println(); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /rest_test/src/main/java/xpadro/tutorial/rest/exception/ProductNotFoundException.java: -------------------------------------------------------------------------------- 1 | package xpadro.tutorial.rest.exception; 2 | 3 | /** 4 | * A runtime exception that arises when a warehouse doesn't contain a specified product 5 | * @author xpadro 6 | * 7 | */ 8 | public class ProductNotFoundException extends RuntimeException { 9 | private static final long serialVersionUID = -4372776309073614775L; 10 | 11 | public ProductNotFoundException(String productId) { 12 | super(productId); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /rest_test/src/main/java/xpadro/tutorial/rest/model/Product.java: -------------------------------------------------------------------------------- 1 | package xpadro.tutorial.rest.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * A product contained in a warehouse. 7 | * @author xpadro 8 | * 9 | */ 10 | public class Product implements Serializable { 11 | private static final long serialVersionUID = 1018938490349056134L; 12 | private Integer id; 13 | private String description; 14 | 15 | 16 | public Product() { 17 | 18 | } 19 | 20 | public Product(Integer id, String description) { 21 | this.id = id; 22 | this.description = description; 23 | } 24 | 25 | /** 26 | * @return the id 27 | */ 28 | public Integer getId() { 29 | return id; 30 | } 31 | 32 | /** 33 | * @param id the id to set 34 | */ 35 | public void setId(Integer id) { 36 | this.id = id; 37 | } 38 | 39 | /** 40 | * @return the description 41 | */ 42 | public String getDescription() { 43 | return description; 44 | } 45 | 46 | /** 47 | * @param description the description to set 48 | */ 49 | public void setDescription(String description) { 50 | this.description = description; 51 | } 52 | 53 | @Override 54 | public int hashCode() { 55 | final int prime = 31; 56 | int result = 1; 57 | result = prime * result 58 | + ((description == null) ? 0 : description.hashCode()); 59 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 60 | return result; 61 | } 62 | 63 | @Override 64 | public boolean equals(Object obj) { 65 | if (this == obj) 66 | return true; 67 | if (obj == null) 68 | return false; 69 | if (getClass() != obj.getClass()) 70 | return false; 71 | Product other = (Product) obj; 72 | if (description == null) { 73 | if (other.description != null) 74 | return false; 75 | } else if (!description.equals(other.description)) 76 | return false; 77 | if (id == null) { 78 | if (other.id != null) 79 | return false; 80 | } else if (!id.equals(other.id)) 81 | return false; 82 | return true; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /rest_test/src/main/java/xpadro/tutorial/rest/model/Warehouse.java: -------------------------------------------------------------------------------- 1 | package xpadro.tutorial.rest.model; 2 | 3 | import java.io.Serializable; 4 | import java.util.Set; 5 | 6 | import xpadro.tutorial.rest.exception.ProductNotFoundException; 7 | 8 | /** 9 | * A warehouse identified in the system by its id. Each warehouse can contain several products. 10 | * @author xpadro 11 | * 12 | */ 13 | public class Warehouse implements Serializable { 14 | private static final long serialVersionUID = 3944671568023013152L; 15 | private Integer id; 16 | private String name; 17 | private Set products; 18 | 19 | 20 | public Warehouse() { 21 | 22 | } 23 | 24 | public Warehouse(int id, String name) { 25 | this.id = id; 26 | this.name = name; 27 | } 28 | 29 | public Warehouse(int id, String name, Set products) { 30 | this.id = id; 31 | this.name = name; 32 | this.products = products; 33 | } 34 | 35 | 36 | /** 37 | * @return the id 38 | */ 39 | public Integer getId() { 40 | return id; 41 | } 42 | 43 | /** 44 | * @param id the id to set 45 | */ 46 | public void setId(Integer id) { 47 | this.id = id; 48 | } 49 | 50 | /** 51 | * @return the name 52 | */ 53 | public String getName() { 54 | return name; 55 | } 56 | 57 | /** 58 | * @param name the name to set 59 | */ 60 | public void setName(String name) { 61 | this.name = name; 62 | } 63 | 64 | /** 65 | * @return the inventory 66 | */ 67 | public Set getProducts() { 68 | return products; 69 | } 70 | 71 | /** 72 | * @param inventory the inventory to set 73 | */ 74 | public void setProducts(Set products) { 75 | this.products = products; 76 | } 77 | 78 | /** 79 | * Returns a product by its id. Throws an exception if the product can't be found. 80 | * @param productId 81 | * @return the requested product 82 | */ 83 | public Product getProduct(int productId) { 84 | for (Product product:products) { 85 | if (productId == product.getId()) { 86 | return product; 87 | } 88 | } 89 | throw new ProductNotFoundException(String.valueOf(productId)); 90 | } 91 | 92 | /** 93 | * Adds a product to the warehouse's inventory 94 | * @param product 95 | */ 96 | public void addProduct(Product product) { 97 | products.add(product); 98 | } 99 | 100 | /** 101 | * Removes an existing product from the warehouse's inventory 102 | * @param productId 103 | */ 104 | public void removeProduct(int productId) { 105 | for (Product product:products) { 106 | if (productId == product.getId()) { 107 | products.remove(product); 108 | return; 109 | } 110 | } 111 | } 112 | 113 | @Override 114 | public int hashCode() { 115 | final int prime = 31; 116 | int result = 1; 117 | result = prime * result + ((id == null) ? 0 : id.hashCode()); 118 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 119 | return result; 120 | } 121 | 122 | @Override 123 | public boolean equals(Object obj) { 124 | if (this == obj) 125 | return true; 126 | if (obj == null) 127 | return false; 128 | if (getClass() != obj.getClass()) 129 | return false; 130 | Warehouse other = (Warehouse) obj; 131 | if (id == null) { 132 | if (other.id != null) 133 | return false; 134 | } else if (!id.equals(other.id)) 135 | return false; 136 | if (name == null) { 137 | if (other.name != null) 138 | return false; 139 | } else if (!name.equals(other.name)) 140 | return false; 141 | return true; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /rest_test/src/main/java/xpadro/tutorial/rest/repository/WarehouseRepository.java: -------------------------------------------------------------------------------- 1 | package xpadro.tutorial.rest.repository; 2 | 3 | import java.util.Set; 4 | 5 | import xpadro.tutorial.rest.model.Product; 6 | import xpadro.tutorial.rest.model.Warehouse; 7 | 8 | /** 9 | * Manages data from warehouses and its products 10 | * @author xpadro 11 | * 12 | */ 13 | public interface WarehouseRepository { 14 | 15 | /** 16 | * Returns the warehouse identified by the id 17 | * @param id 18 | * @return the warehouse 19 | */ 20 | public Warehouse getWarehouse(Integer id); 21 | 22 | /** 23 | * Creates a new warehouse 24 | * @param warehouse 25 | */ 26 | public void createWarehouse(Warehouse warehouse); 27 | 28 | /** 29 | * Removes an existing warehouse identified by the id 30 | * @param warehouseId 31 | */ 32 | public void removeWarehouse(int warehouseId); 33 | 34 | /** 35 | * Returns the list of all products contained in the warehouse identified by the id 36 | * @param warehouseId 37 | * @return 38 | */ 39 | public Set getProducts(int warehouseId); 40 | 41 | /** 42 | * Gets a product by its id that is contained in the warehouse 43 | * @param warehouseId 44 | * @param productId 45 | * @return the product 46 | */ 47 | public Product getProduct(int warehouseId, int productId); 48 | 49 | /** 50 | * Adds a new product to an existing warehouse 51 | * @param warehouseId 52 | * @param product 53 | */ 54 | public void addProduct(int warehouseId, Product product); 55 | 56 | /** 57 | * Removes an existing product identified by the id 58 | * @param warehouseId 59 | * @param productId 60 | */ 61 | public void removeProduct(int warehouseId, int productId); 62 | } 63 | -------------------------------------------------------------------------------- /rest_test/src/main/java/xpadro/tutorial/rest/repository/WarehouseRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package xpadro.tutorial.rest.repository; 2 | 3 | import java.util.HashMap; 4 | import java.util.HashSet; 5 | import java.util.Map; 6 | import java.util.Set; 7 | 8 | import org.springframework.stereotype.Repository; 9 | 10 | import xpadro.tutorial.rest.model.Product; 11 | import xpadro.tutorial.rest.model.Warehouse; 12 | 13 | /** 14 | * A stub repository that uses dummy data for testing 15 | * @author xpadro 16 | * 17 | */ 18 | @Repository 19 | public class WarehouseRepositoryImpl implements WarehouseRepository { 20 | private Map warehouses; 21 | 22 | 23 | public WarehouseRepositoryImpl() { 24 | warehouses = new HashMap(); 25 | createDummyWarehouses(); 26 | } 27 | 28 | @Override 29 | public Warehouse getWarehouse(Integer id) { 30 | return warehouses.get(id); 31 | } 32 | 33 | @Override 34 | public void createWarehouse(Warehouse warehouse) { 35 | warehouses.put(warehouse.getId(), warehouse); 36 | } 37 | 38 | @Override 39 | public void removeWarehouse(int warehouseId) { 40 | warehouses.remove(warehouseId); 41 | } 42 | 43 | @Override 44 | public Set getProducts(int warehouseId) { 45 | return warehouses.get(warehouseId).getProducts(); 46 | } 47 | 48 | @Override 49 | public Product getProduct(int warehouseId, int productId) { 50 | return warehouses.get(warehouseId).getProduct(productId); 51 | } 52 | 53 | @Override 54 | public void addProduct(int warehouseId, Product product) { 55 | warehouses.get(warehouseId).addProduct(product); 56 | } 57 | 58 | @Override 59 | public void removeProduct(int warehouseId, int productId) { 60 | warehouses.get(warehouseId).removeProduct(productId); 61 | } 62 | 63 | private void createDummyWarehouses() { 64 | Set products = new HashSet(); 65 | Product product = new Product(1, "PROD_004"); 66 | products.add(product); 67 | product = new Product(2, "PROD_015"); 68 | products.add(product); 69 | product = new Product(3, "PROD_125"); 70 | products.add(product); 71 | Warehouse warehouse = new Warehouse(1, "WAR_BCN_004", products); 72 | 73 | warehouses.put(1, warehouse); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /rest_test/src/main/resources/xpadro/tutorial/rest/configuration/app-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /rest_test/src/main/resources/xpadro/tutorial/rest/configuration/root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /rest_test/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SpringRestTest 4 | 5 | 6 | 7 | contextConfigLocation 8 | classpath:xpadro/tutorial/rest/configuration/root-context.xml 9 | 10 | 11 | 12 | 13 | org.springframework.web.context.ContextLoaderListener 14 | 15 | 16 | 17 | 18 | springServlet 19 | org.springframework.web.servlet.DispatcherServlet 20 | 21 | contextConfigLocation 22 | classpath:xpadro/tutorial/rest/configuration/app-context.xml 23 | 24 | 25 | 26 | springServlet 27 | /spring/* 28 | 29 | -------------------------------------------------------------------------------- /rest_test/src/test/java/xpadro/tutorial/rest/client/TestWarehouse.java: -------------------------------------------------------------------------------- 1 | package xpadro.tutorial.rest.client; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.net.URI; 7 | 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.http.HttpStatus; 11 | import org.springframework.test.context.ContextConfiguration; 12 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 13 | import org.springframework.web.client.HttpClientErrorException; 14 | import org.springframework.web.client.RestTemplate; 15 | 16 | import xpadro.tutorial.rest.model.Product; 17 | import xpadro.tutorial.rest.model.Warehouse; 18 | 19 | @RunWith(SpringJUnit4ClassRunner.class) 20 | @ContextConfiguration(locations={ 21 | "classpath:xpadro/tutorial/rest/configuration/root-context.xml", 22 | "classpath:xpadro/tutorial/rest/configuration/app-context.xml"}) 23 | public class TestWarehouse { 24 | private static final int WAREHOUSE_ID = 1; 25 | private static final int PRODUCT_ID = 4; 26 | 27 | private RestTemplate restTemplate = new RestTemplate(); 28 | 29 | /** 30 | * Tests accessing to an existing warehouse 31 | */ 32 | @Test 33 | public void getWarehouse() { 34 | String uri = "http://localhost:8080/rest_test/spring/warehouses/{warehouseId}"; 35 | Warehouse warehouse = restTemplate.getForObject(uri, Warehouse.class, WAREHOUSE_ID); 36 | assertNotNull(warehouse); 37 | assertEquals("WAR_BCN_004", warehouse.getName()); 38 | } 39 | 40 | /** 41 | * Tests the addition of a new product to an existing warehouse. 42 | */ 43 | @Test 44 | public void addProduct() { 45 | //Adds the new product 46 | String uri = "http://localhost:8080/rest_test/spring/warehouses/{warehouseId}/products"; 47 | Product product = new Product(PRODUCT_ID, "PROD_999"); 48 | URI newProductLocation = restTemplate.postForLocation(uri, product, WAREHOUSE_ID); 49 | 50 | //Checks we can access to the created product 51 | Product createdProduct = restTemplate.getForObject(newProductLocation, Product.class); 52 | assertEquals(product, createdProduct); 53 | assertNotNull(createdProduct.getId()); 54 | } 55 | 56 | /** 57 | * Tests the removal of an existing product 58 | */ 59 | @Test 60 | public void removeProduct() { 61 | String uri = "http://localhost:8080/rest_test/spring/warehouses/{warehouseId}/products/{productId}"; 62 | restTemplate.delete(uri, WAREHOUSE_ID, PRODUCT_ID); 63 | 64 | try { 65 | restTemplate.getForObject(uri, Product.class, WAREHOUSE_ID, PRODUCT_ID); 66 | throw new AssertionError("Should have returned an 404 error code"); 67 | } catch (HttpClientErrorException e) { 68 | assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode()); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.gitignore: -------------------------------------------------------------------------------- 1 | target -------------------------------------------------------------------------------- /spring-rest-api-v32/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | spring-rest-api-v32 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | org.springframework.ide.eclipse.core.springbuilder 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.ide.eclipse.core.springnature 41 | org.eclipse.jem.workbench.JavaEMFNature 42 | org.eclipse.wst.common.modulecore.ModuleCoreNature 43 | org.eclipse.jdt.core.javanature 44 | org.eclipse.m2e.core.maven2Nature 45 | org.eclipse.wst.common.project.facet.core.nature 46 | org.eclipse.wst.jsdt.core.jsNature 47 | 48 | 49 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.7 9 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /spring-rest-api-v32/.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /spring-rest-api-v32/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | xpadro.spring.web 5 | spring-rest-api-v32 6 | war 7 | 0.0.1-SNAPSHOT 8 | spring-rest-api-v32 Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | 3.2.3.RELEASE 13 | 1.3.3.RELEASE 14 | 2.5 15 | 1.2 16 | 4.8.1 17 | 1.4.2 18 | 1.7.2 19 | 1.2.16 20 | 1.3 21 | 1.9.5 22 | 0.8.1 23 | 1.4.2 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.springframework 32 | spring-context 33 | ${spring.version} 34 | 35 | 36 | org.springframework 37 | spring-webmvc 38 | ${spring.version} 39 | 40 | 41 | 42 | 43 | org.springframework.data 44 | spring-data-mongodb 45 | ${spring.mongo.version} 46 | 47 | 48 | org.slf4j 49 | slf4j-api 50 | 51 | 52 | 53 | 54 | 55 | 56 | javax.servlet 57 | servlet-api 58 | ${servlet.version} 59 | provided 60 | 61 | 62 | javax.servlet 63 | jstl 64 | ${jstl.version} 65 | 66 | 67 | 68 | 69 | org.slf4j 70 | slf4j-log4j12 71 | ${slf4j.version} 72 | 73 | 74 | log4j 75 | log4j 76 | ${log4j.version} 77 | 78 | 79 | 80 | 81 | org.springframework 82 | spring-test 83 | ${spring.version} 84 | test 85 | 86 | 87 | org.hamcrest 88 | hamcrest-all 89 | ${hamcrest.version} 90 | test 91 | 92 | 93 | junit 94 | junit 95 | ${junit.version} 96 | test 97 | 98 | 99 | hamcrest-core 100 | org.hamcrest 101 | 102 | 103 | 104 | 105 | org.mockito 106 | mockito-core 107 | ${mockito.version} 108 | test 109 | 110 | 111 | org.hamcrest 112 | hamcrest-core 113 | 114 | 115 | 116 | 117 | com.jayway.jsonpath 118 | json-path-assert 119 | ${jsonpath.version} 120 | test 121 | 122 | 123 | 124 | 125 | org.codehaus.jackson 126 | jackson-mapper-asl 127 | ${jackson.version} 128 | 129 | 130 | 131 | 132 | 133 | spring-rest-api-v32 134 | 135 | 136 | maven-compiler-plugin 137 | 138 | 1.7 139 | 1.7 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/java/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/java/xpadro/spring/web/controller/SeriesController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.controller; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.stereotype.Controller; 10 | import org.springframework.web.bind.annotation.PathVariable; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestMethod; 14 | import org.springframework.web.bind.annotation.ResponseBody; 15 | import org.springframework.web.bind.annotation.ResponseStatus; 16 | 17 | import xpadro.spring.web.model.Series; 18 | import xpadro.spring.web.service.SeriesService; 19 | 20 | @Controller 21 | @RequestMapping(value="/series") 22 | public class SeriesController { 23 | 24 | private SeriesService seriesService; 25 | 26 | @Autowired 27 | public SeriesController(SeriesService seriesService) { 28 | this.seriesService = seriesService; 29 | } 30 | 31 | 32 | /** 33 | * Returns all registered series 34 | * @return 35 | */ 36 | @RequestMapping(method=RequestMethod.GET) 37 | @ResponseBody 38 | public Series[] getAllSeries() { 39 | return seriesService.getAllSeries(); 40 | } 41 | 42 | /** 43 | * Returns the requested series by its id. 44 | * @param id 45 | * @return The requested series 46 | */ 47 | @RequestMapping(value="/{seriesId}", method=RequestMethod.GET) 48 | public ResponseEntity getSeries(@PathVariable("seriesId") long id) { 49 | Series series = seriesService.getSeries(id); 50 | 51 | if (series == null) { 52 | return new ResponseEntity(HttpStatus.NOT_FOUND); 53 | } 54 | 55 | return new ResponseEntity(series, HttpStatus.OK); 56 | } 57 | 58 | /** 59 | * Inserts a new series to the DB 60 | * @param series 61 | * @param request 62 | * @param response 63 | */ 64 | @RequestMapping(method=RequestMethod.POST) 65 | @ResponseStatus(HttpStatus.CREATED) 66 | public void insertSeries(@RequestBody Series series, HttpServletRequest request, HttpServletResponse response) { 67 | seriesService.insertSeries(series); 68 | response.setHeader("Location", request.getRequestURL().append("/").append(series.getId()).toString()); 69 | } 70 | 71 | /** 72 | * Deletes the specified series 73 | * @param id 74 | */ 75 | @RequestMapping(value="/{seriesId}", method=RequestMethod.DELETE) 76 | @ResponseStatus(HttpStatus.NO_CONTENT) 77 | public void deleteSeries(@PathVariable("seriesId") long id) { 78 | seriesService.deleteSeries(id); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/java/xpadro/spring/web/model/Series.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.xml.bind.annotation.XmlElement; 6 | import javax.xml.bind.annotation.XmlRootElement; 7 | 8 | @XmlRootElement(name="series") 9 | public class Series implements Serializable { 10 | private static final long serialVersionUID = 2646831820313826686L; 11 | 12 | private long id; 13 | private String name; 14 | private String country; 15 | private String genre; 16 | 17 | public Series() {} 18 | 19 | public Series(long id, String name, String country, String genre) { 20 | this.id = id; 21 | this.name = name; 22 | this.country = country; 23 | this.genre = genre; 24 | } 25 | 26 | @XmlElement 27 | public long getId() { 28 | return id; 29 | } 30 | 31 | public void setId(long id) { 32 | this.id = id; 33 | } 34 | 35 | @XmlElement 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | @XmlElement 45 | public String getCountry() { 46 | return country; 47 | } 48 | 49 | public void setCountry(String country) { 50 | this.country = country; 51 | } 52 | 53 | @XmlElement 54 | public String getGenre() { 55 | return genre; 56 | } 57 | 58 | public void setGenre(String genre) { 59 | this.genre = genre; 60 | } 61 | 62 | 63 | 64 | /* 65 | private Series(SeriesBuilder builder) { 66 | id = builder.id; 67 | name = builder.name; 68 | country = builder.country; 69 | genre = builder.genre; 70 | } 71 | 72 | 73 | 74 | public long getId() { 75 | return id; 76 | } 77 | 78 | 79 | public String getName() { 80 | return name; 81 | } 82 | 83 | 84 | public String getCountry() { 85 | return country; 86 | } 87 | 88 | 89 | public String getGenre() { 90 | return genre; 91 | } 92 | 93 | 94 | public static class SeriesBuilder { 95 | private final long id; 96 | private final String name; 97 | 98 | private String country; 99 | private String genre; 100 | 101 | 102 | public SeriesBuilder(long id, String name) { 103 | this.id = id; 104 | this.name = name; 105 | } 106 | 107 | 108 | public SeriesBuilder withCountry(String country) { 109 | this.country = country; 110 | return this; 111 | } 112 | 113 | public SeriesBuilder withGenre(String genre) { 114 | this.genre = genre; 115 | return this; 116 | } 117 | 118 | public Series build() { 119 | return new Series(this); 120 | } 121 | } 122 | */ 123 | } 124 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/java/xpadro/spring/web/service/SeriesService.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.service; 2 | 3 | import xpadro.spring.web.model.Series; 4 | 5 | /** 6 | * Manages data from series 7 | * @author xpadro 8 | * 9 | */ 10 | public interface SeriesService { 11 | 12 | /** 13 | * Returns all series 14 | * @return 15 | */ 16 | Series[] getAllSeries(); 17 | 18 | /** 19 | * Returns the series identified by the id 20 | * @param id 21 | * @return the series 22 | */ 23 | Series getSeries(long id); 24 | 25 | /** 26 | * Inserts a series into the DB 27 | * @param series 28 | */ 29 | void insertSeries(Series series); 30 | 31 | /** 32 | * Deletes the specified series 33 | * @param id 34 | */ 35 | void deleteSeries(long id); 36 | } 37 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/java/xpadro/spring/web/service/impl/SeriesServiceImpl.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.service.impl; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.mongodb.core.MongoOperations; 7 | import org.springframework.data.mongodb.core.query.Criteria; 8 | import org.springframework.data.mongodb.core.query.Query; 9 | import org.springframework.stereotype.Service; 10 | 11 | import xpadro.spring.web.model.Series; 12 | import xpadro.spring.web.service.SeriesService; 13 | 14 | /** 15 | * Handles data using a mongoDB database 16 | * @author xpadro 17 | * 18 | */ 19 | @Service 20 | public class SeriesServiceImpl implements SeriesService { 21 | 22 | @Autowired 23 | private MongoOperations mongoOps; 24 | 25 | 26 | @Override 27 | public Series[] getAllSeries() { 28 | List seriesList = mongoOps.findAll(Series.class); 29 | return seriesList.toArray(new Series[0]); 30 | } 31 | 32 | @Override 33 | public Series getSeries(long id) { 34 | return mongoOps.findById(id, Series.class); 35 | } 36 | 37 | @Override 38 | public void insertSeries(Series series) { 39 | mongoOps.insert(series); 40 | } 41 | 42 | 43 | @Override 44 | public void deleteSeries(long id) { 45 | Query query = new Query(); 46 | Criteria criteria = new Criteria("_id").is(id); 47 | query.addCriteria(criteria); 48 | 49 | mongoOps.remove(query, Series.class); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/resources/xpadro/spring/web/configuration/app-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/resources/xpadro/spring/web/configuration/db-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/resources/xpadro/spring/web/configuration/root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Spring MVC - RESTful web services 7 | 8 | 9 | 10 | contextConfigLocation 11 | classpath:xpadro/spring/web/configuration/root-context.xml 12 | 13 | 14 | 15 | 16 | org.springframework.web.context.ContextLoaderListener 17 | 18 | 19 | 20 | 21 | springServlet 22 | org.springframework.web.servlet.DispatcherServlet 23 | 24 | contextConfigLocation 25 | classpath:xpadro/spring/web/configuration/app-context.xml 26 | 27 | 28 | 29 | springServlet 30 | /spring/* 31 | 32 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

RESTful Web Services with Spring MVC

4 | 5 | 6 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/test/java/xpadro/spring/web/test/SeriesFunctionalTesting.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.test; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.fail; 6 | 7 | import java.net.URI; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import org.junit.Before; 12 | import org.junit.Test; 13 | import org.junit.runner.RunWith; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.dao.DataAccessResourceFailureException; 16 | import org.springframework.data.mongodb.core.MongoOperations; 17 | import org.springframework.http.HttpStatus; 18 | import org.springframework.http.MediaType; 19 | import org.springframework.http.ResponseEntity; 20 | import org.springframework.http.converter.HttpMessageConverter; 21 | import org.springframework.http.converter.StringHttpMessageConverter; 22 | import org.springframework.http.converter.json.MappingJacksonHttpMessageConverter; 23 | import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; 24 | import org.springframework.test.context.ContextConfiguration; 25 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 26 | import org.springframework.web.client.HttpClientErrorException; 27 | import org.springframework.web.client.RestTemplate; 28 | 29 | import xpadro.spring.web.model.Series; 30 | 31 | @RunWith(SpringJUnit4ClassRunner.class) 32 | @ContextConfiguration(locations={ 33 | "classpath:xpadro/spring/web/configuration/root-context.xml", 34 | "classpath:xpadro/spring/web/configuration/app-context.xml"}) 35 | public class SeriesFunctionalTesting { 36 | private static final String BASE_URI = "http://localhost:8080/spring-rest-api-v32/spring/series"; 37 | private RestTemplate restTemplate = new RestTemplate(); 38 | 39 | @Autowired 40 | private MongoOperations mongoOps; 41 | 42 | @Before 43 | public void setup() { 44 | List> converters = new ArrayList>(); 45 | converters.add(new StringHttpMessageConverter()); 46 | converters.add(new Jaxb2RootElementHttpMessageConverter()); 47 | converters.add(new MappingJacksonHttpMessageConverter()); 48 | restTemplate.setMessageConverters(converters); 49 | 50 | initializeDatabase(); 51 | } 52 | 53 | private void initializeDatabase() { 54 | try { 55 | mongoOps.dropCollection("series"); 56 | 57 | mongoOps.insert(new Series(1, "The walking dead", "USA", "Thriller")); 58 | mongoOps.insert(new Series(2, "Homeland", "USA", "Drama")); 59 | } catch (DataAccessResourceFailureException e) { 60 | fail("MongoDB instance is not running"); 61 | } 62 | } 63 | 64 | 65 | @Test 66 | public void getAllSeries() { 67 | Series[] series = restTemplate.getForObject(BASE_URI, Series[].class); 68 | 69 | assertNotNull(series); 70 | assertEquals(2, series.length); 71 | assertEquals(1L, series[0].getId()); 72 | assertEquals("The walking dead", series[0].getName()); 73 | assertEquals("USA", series[0].getCountry()); 74 | assertEquals("Thriller", series[0].getGenre()); 75 | assertEquals(2L, series[1].getId()); 76 | assertEquals("Homeland", series[1].getName()); 77 | assertEquals("USA", series[1].getCountry()); 78 | assertEquals("Drama", series[1].getGenre()); 79 | } 80 | 81 | 82 | @Test 83 | public void getJsonSeries() { 84 | List> converters = new ArrayList>(); 85 | converters.add(new MappingJacksonHttpMessageConverter()); 86 | restTemplate.setMessageConverters(converters); 87 | 88 | String uri = BASE_URI + "/{seriesId}"; 89 | ResponseEntity seriesEntity = restTemplate.getForEntity(uri, Series.class, 1l); 90 | assertNotNull(seriesEntity.getBody()); 91 | assertEquals(1l, seriesEntity.getBody().getId()); 92 | assertEquals("The walking dead", seriesEntity.getBody().getName()); 93 | assertEquals("USA", seriesEntity.getBody().getCountry()); 94 | assertEquals("Thriller", seriesEntity.getBody().getGenre()); 95 | 96 | assertEquals(MediaType.parseMediaType("application/json;charset=UTF-8"), seriesEntity.getHeaders().getContentType()); 97 | } 98 | 99 | @Test 100 | public void getXmlSeries() { 101 | String uri = BASE_URI + "/{seriesId}"; 102 | ResponseEntity seriesEntity = restTemplate.getForEntity(uri, Series.class, 1L); 103 | assertNotNull(seriesEntity.getBody()); 104 | assertEquals(1l, seriesEntity.getBody().getId()); 105 | assertEquals("The walking dead", seriesEntity.getBody().getName()); 106 | assertEquals("USA", seriesEntity.getBody().getCountry()); 107 | assertEquals("Thriller", seriesEntity.getBody().getGenre()); 108 | 109 | assertEquals(MediaType.APPLICATION_XML, seriesEntity.getHeaders().getContentType()); 110 | } 111 | 112 | @Test 113 | public void getNotFoundSeries() { 114 | String uri = BASE_URI + "/{seriesId}"; 115 | 116 | try { 117 | restTemplate.getForEntity(uri, Series.class, 5L); 118 | } catch (HttpClientErrorException e) { 119 | assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode()); 120 | } 121 | } 122 | 123 | @Test 124 | public void insertNewSeries() { 125 | Series series = new Series(); 126 | series.setId(4L); 127 | series.setName("mySeries"); 128 | series.setCountry("England"); 129 | series.setGenre("sci-fi"); 130 | 131 | URI newUserLocation = restTemplate.postForLocation(BASE_URI, series); 132 | assertEquals(BASE_URI + "/4", newUserLocation.toString()); 133 | } 134 | 135 | @Test 136 | public void deleteExistingSeries() { 137 | String uri = BASE_URI + "/{seriesId}"; 138 | restTemplate.delete(uri, 2L); 139 | 140 | try { 141 | restTemplate.getForEntity(uri, Series.class, 2L); 142 | } catch (HttpClientErrorException e) { 143 | assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode()); 144 | } 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/test/java/xpadro/spring/web/test/SeriesIntegrationTesting.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.test; 2 | 3 | import static org.hamcrest.Matchers.hasSize; 4 | import static org.hamcrest.Matchers.is; 5 | import static org.hamcrest.Matchers.endsWith; 6 | import static org.mockito.Mockito.*; 7 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 8 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | import org.springframework.test.context.web.WebAppConfiguration; 12 | import org.springframework.test.web.servlet.MockMvc; 13 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.junit.runner.RunWith; 17 | 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.web.context.WebApplicationContext; 20 | import org.springframework.http.MediaType; 21 | 22 | import xpadro.spring.web.model.Series; 23 | import xpadro.spring.web.service.SeriesService; 24 | 25 | @RunWith(SpringJUnit4ClassRunner.class) 26 | @WebAppConfiguration 27 | @ContextConfiguration(locations={ 28 | "classpath:xpadro/spring/web/test/configuration/test-root-context.xml", 29 | "classpath:xpadro/spring/web/configuration/app-context.xml"}) 30 | public class SeriesIntegrationTesting { 31 | private static final String BASE_URI = "/series"; 32 | 33 | private MockMvc mockMvc; 34 | 35 | @Autowired 36 | private WebApplicationContext webApplicationContext; 37 | 38 | @Autowired 39 | private SeriesService seriesService; 40 | 41 | 42 | @Before 43 | public void setUp() { 44 | reset(seriesService); 45 | mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 46 | 47 | when(seriesService.getAllSeries()).thenReturn(new Series[]{ 48 | new Series(1, "The walking dead", "USA", "Thriller"), 49 | new Series(2, "Homeland", "USA", "Drama")}); 50 | 51 | when(seriesService.getSeries(1L)).thenReturn(new Series(1, "Fringe", "USA", "Thriller")); 52 | } 53 | 54 | 55 | @Test 56 | public void getAllSeries() throws Exception { 57 | mockMvc.perform(get(BASE_URI) 58 | .accept(MediaType.APPLICATION_JSON)) 59 | .andExpect(status().isOk()) 60 | .andExpect(content().contentType("application/json;charset=UTF-8")) 61 | .andExpect(jsonPath("$", hasSize(2))) 62 | .andExpect(jsonPath("$[0].id", is(1))) 63 | .andExpect(jsonPath("$[0].name", is("The walking dead"))) 64 | .andExpect(jsonPath("$[0].country", is("USA"))) 65 | .andExpect(jsonPath("$[0].genre", is("Thriller"))) 66 | .andExpect(jsonPath("$[1].id", is(2))) 67 | .andExpect(jsonPath("$[1].name", is("Homeland"))) 68 | .andExpect(jsonPath("$[1].country", is("USA"))) 69 | .andExpect(jsonPath("$[1].genre", is("Drama"))); 70 | 71 | verify(seriesService, times(1)).getAllSeries(); 72 | verifyZeroInteractions(seriesService); 73 | } 74 | 75 | @Test 76 | public void getJsonSeries() throws Exception { 77 | mockMvc.perform(get(BASE_URI + "/{seriesId}", 1L) 78 | .accept(MediaType.APPLICATION_JSON)) 79 | .andExpect(status().isOk()) 80 | .andExpect(content().contentType("application/json;charset=UTF-8")) 81 | .andExpect(jsonPath("$.id", is(1))) 82 | .andExpect(jsonPath("$.name", is("Fringe"))) 83 | .andExpect(jsonPath("$.country", is("USA"))) 84 | .andExpect(jsonPath("$.genre", is("Thriller"))); 85 | 86 | verify(seriesService, times(1)).getSeries(1L); 87 | verifyZeroInteractions(seriesService); 88 | } 89 | 90 | @Test 91 | public void getXmlSeries() throws Exception { 92 | mockMvc.perform(get(BASE_URI + "/{seriesId}", 1L) 93 | .accept(MediaType.APPLICATION_XML)) 94 | .andExpect(status().isOk()) 95 | .andExpect(content().contentType(MediaType.APPLICATION_XML)) 96 | .andExpect(xpath("/series/id").string("1")) 97 | .andExpect(xpath("/series/name").string("Fringe")) 98 | .andExpect(xpath("/series/country").string("USA")) 99 | .andExpect(xpath("/series/genre").string("Thriller")); 100 | 101 | 102 | verify(seriesService, times(1)).getSeries(1L); 103 | verifyZeroInteractions(seriesService); 104 | } 105 | 106 | @Test 107 | public void getNotFoundSeries() throws Exception { 108 | mockMvc.perform(get(BASE_URI + "/{seriesId}", 5L) 109 | .accept(MediaType.APPLICATION_JSON)) 110 | .andExpect(status().isNotFound()); 111 | 112 | verify(seriesService, times(1)).getSeries(5L); 113 | verifyZeroInteractions(seriesService); 114 | } 115 | 116 | @Test 117 | public void insertNewSeries() throws Exception { 118 | mockMvc.perform(post(BASE_URI) 119 | .content("{ \"id\": 3, \"name\": \"mySeries\", \"country\": \"England\", \"genre\": \"sci-fi\" } }") 120 | .contentType(MediaType.APPLICATION_JSON) 121 | .accept(MediaType.APPLICATION_JSON)) 122 | .andExpect(status().isCreated()) 123 | .andExpect(header().string("Location", endsWith("/series/3"))); 124 | 125 | verify(seriesService, times(1)).insertSeries(any(Series.class)); 126 | verifyZeroInteractions(seriesService); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /spring-rest-api-v32/src/test/resources/xpadro/spring/web/test/configuration/test-root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | spring-rest-api-v4 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.springframework.ide.eclipse.core.springbuilder 30 | 31 | 32 | 33 | 34 | org.eclipse.m2e.core.maven2Builder 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.ide.eclipse.core.springnature 41 | org.eclipse.jem.workbench.JavaEMFNature 42 | org.eclipse.wst.common.modulecore.ModuleCoreNature 43 | org.eclipse.jdt.core.javanature 44 | org.eclipse.m2e.core.maven2Nature 45 | org.eclipse.wst.common.project.facet.core.nature 46 | org.eclipse.wst.jsdt.core.jsNature 47 | 48 | 49 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.compliance=1.7 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.source=1.7 9 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /spring-rest-api-v4/.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /spring-rest-api-v4/environment/development/workspace/spring-rest-api-v4/target/m2e-wtp/web-resources/.gitignore: -------------------------------------------------------------------------------- 1 | /META-INF 2 | -------------------------------------------------------------------------------- /spring-rest-api-v4/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | xpadro.spring.web 5 | spring-rest-api-v4 6 | war 7 | 0.0.1-SNAPSHOT 8 | spring-rest-api-v4 Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | 4.0.0.RELEASE 13 | 1.3.3.RELEASE 14 | 3.1.0 15 | 1.2 16 | 4.8.1 17 | 1.4.2 18 | 1.7.2 19 | 1.2.16 20 | 1.3 21 | 1.9.5 22 | 0.8.1 23 | 1.4.2 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | org.springframework 32 | spring-context 33 | ${spring.version} 34 | 35 | 36 | org.springframework 37 | spring-webmvc 38 | ${spring.version} 39 | 40 | 41 | 42 | 43 | org.springframework.data 44 | spring-data-mongodb 45 | ${spring.mongo.version} 46 | 47 | 48 | org.slf4j 49 | slf4j-api 50 | 51 | 52 | 53 | 54 | 55 | 56 | javax.servlet 57 | javax.servlet-api 58 | ${servlet.version} 59 | provided 60 | 61 | 62 | 63 | javax.servlet 64 | jstl 65 | ${jstl.version} 66 | 67 | 68 | 69 | 70 | org.slf4j 71 | slf4j-log4j12 72 | ${slf4j.version} 73 | 74 | 75 | log4j 76 | log4j 77 | ${log4j.version} 78 | 79 | 80 | 81 | 82 | org.springframework 83 | spring-test 84 | ${spring.version} 85 | test 86 | 87 | 88 | org.hamcrest 89 | hamcrest-all 90 | ${hamcrest.version} 91 | test 92 | 93 | 94 | junit 95 | junit 96 | ${junit.version} 97 | test 98 | 99 | 100 | hamcrest-core 101 | org.hamcrest 102 | 103 | 104 | 105 | 106 | org.mockito 107 | mockito-core 108 | ${mockito.version} 109 | test 110 | 111 | 112 | org.hamcrest 113 | hamcrest-core 114 | 115 | 116 | 117 | 118 | com.jayway.jsonpath 119 | json-path-assert 120 | ${jsonpath.version} 121 | test 122 | 123 | 124 | 125 | 132 | 133 | com.fasterxml.jackson.core 134 | jackson-core 135 | 2.3.0 136 | 137 | 138 | com.fasterxml.jackson.core 139 | jackson-databind 140 | 2.3.0 141 | 142 | 143 | 144 | 145 | 146 | 147 | spring-rest-api-v4 148 | 149 | 150 | maven-compiler-plugin 151 | 152 | 1.7 153 | 1.7 154 | 155 | 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/java/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/java/xpadro/spring/web/controller/SeriesController.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.controller; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.http.ResponseEntity; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.RequestBody; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RequestMethod; 13 | import org.springframework.web.bind.annotation.ResponseStatus; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | import xpadro.spring.web.model.Series; 17 | import xpadro.spring.web.service.SeriesService; 18 | 19 | @RestController 20 | @RequestMapping(value="/series") 21 | public class SeriesController { 22 | 23 | private SeriesService seriesService; 24 | 25 | @Autowired 26 | public SeriesController(SeriesService seriesService) { 27 | this.seriesService = seriesService; 28 | } 29 | 30 | 31 | /** 32 | * Returns all registered series 33 | * @return 34 | * @throws InterruptedException 35 | */ 36 | @RequestMapping(method=RequestMethod.GET) 37 | public Series[] getAllSeries() throws InterruptedException { 38 | Thread.sleep(4000); //pause to better show sync/async RestTemplate behavior 39 | return seriesService.getAllSeries(); 40 | } 41 | 42 | /** 43 | * Returns the requested series by its id. 44 | * @param id 45 | * @return The requested series 46 | */ 47 | @RequestMapping(value="/{seriesId}", method=RequestMethod.GET) 48 | public ResponseEntity getSeries(@PathVariable("seriesId") long id) { 49 | Series series = seriesService.getSeries(id); 50 | 51 | if (series == null) { 52 | return new ResponseEntity(HttpStatus.NOT_FOUND); 53 | } 54 | 55 | return new ResponseEntity(series, HttpStatus.OK); 56 | } 57 | 58 | /** 59 | * Inserts a new series to the DB 60 | * @param series 61 | * @param request 62 | * @param response 63 | */ 64 | @RequestMapping(method=RequestMethod.POST) 65 | @ResponseStatus(HttpStatus.CREATED) 66 | public void insertSeries(@RequestBody Series series, HttpServletRequest request, HttpServletResponse response) { 67 | seriesService.insertSeries(series); 68 | response.setHeader("Location", request.getRequestURL().append("/").append(series.getId()).toString()); 69 | } 70 | 71 | /** 72 | * Deletes the specified series 73 | * @param id 74 | */ 75 | @RequestMapping(value="/{seriesId}", method=RequestMethod.DELETE) 76 | @ResponseStatus(HttpStatus.NO_CONTENT) 77 | public void deleteSeries(@PathVariable("seriesId") long id) { 78 | seriesService.deleteSeries(id); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/java/xpadro/spring/web/model/Series.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import javax.xml.bind.annotation.XmlElement; 6 | import javax.xml.bind.annotation.XmlRootElement; 7 | 8 | @XmlRootElement(name="series") 9 | public class Series implements Serializable { 10 | private static final long serialVersionUID = 2646831820313826686L; 11 | 12 | private long id; 13 | private String name; 14 | private String country; 15 | private String genre; 16 | 17 | public Series() {} 18 | 19 | public Series(long id, String name, String country, String genre) { 20 | this.id = id; 21 | this.name = name; 22 | this.country = country; 23 | this.genre = genre; 24 | } 25 | 26 | @XmlElement 27 | public long getId() { 28 | return id; 29 | } 30 | 31 | public void setId(long id) { 32 | this.id = id; 33 | } 34 | 35 | @XmlElement 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | @XmlElement 45 | public String getCountry() { 46 | return country; 47 | } 48 | 49 | public void setCountry(String country) { 50 | this.country = country; 51 | } 52 | 53 | @XmlElement 54 | public String getGenre() { 55 | return genre; 56 | } 57 | 58 | public void setGenre(String genre) { 59 | this.genre = genre; 60 | } 61 | 62 | 63 | 64 | /* 65 | private Series(SeriesBuilder builder) { 66 | id = builder.id; 67 | name = builder.name; 68 | country = builder.country; 69 | genre = builder.genre; 70 | } 71 | 72 | 73 | 74 | public long getId() { 75 | return id; 76 | } 77 | 78 | 79 | public String getName() { 80 | return name; 81 | } 82 | 83 | 84 | public String getCountry() { 85 | return country; 86 | } 87 | 88 | 89 | public String getGenre() { 90 | return genre; 91 | } 92 | 93 | 94 | public static class SeriesBuilder { 95 | private final long id; 96 | private final String name; 97 | 98 | private String country; 99 | private String genre; 100 | 101 | 102 | public SeriesBuilder(long id, String name) { 103 | this.id = id; 104 | this.name = name; 105 | } 106 | 107 | 108 | public SeriesBuilder withCountry(String country) { 109 | this.country = country; 110 | return this; 111 | } 112 | 113 | public SeriesBuilder withGenre(String genre) { 114 | this.genre = genre; 115 | return this; 116 | } 117 | 118 | public Series build() { 119 | return new Series(this); 120 | } 121 | } 122 | */ 123 | } 124 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/java/xpadro/spring/web/service/SeriesService.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.service; 2 | 3 | import xpadro.spring.web.model.Series; 4 | 5 | /** 6 | * Manages data from series 7 | * @author xpadro 8 | * 9 | */ 10 | public interface SeriesService { 11 | 12 | /** 13 | * Returns all series 14 | * @return 15 | */ 16 | Series[] getAllSeries(); 17 | 18 | /** 19 | * Returns the series identified by the id 20 | * @param id 21 | * @return the series 22 | */ 23 | Series getSeries(long id); 24 | 25 | /** 26 | * Inserts a series into the DB 27 | * @param series 28 | */ 29 | void insertSeries(Series series); 30 | 31 | /** 32 | * Deletes the specified series 33 | * @param id 34 | */ 35 | void deleteSeries(long id); 36 | } 37 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/java/xpadro/spring/web/service/impl/SeriesServiceImpl.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.service.impl; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.data.mongodb.core.MongoOperations; 7 | import org.springframework.data.mongodb.core.query.Criteria; 8 | import org.springframework.data.mongodb.core.query.Query; 9 | import org.springframework.stereotype.Service; 10 | 11 | import xpadro.spring.web.model.Series; 12 | import xpadro.spring.web.service.SeriesService; 13 | 14 | /** 15 | * Handles data using a mongoDB database 16 | * @author xpadro 17 | * 18 | */ 19 | @Service 20 | public class SeriesServiceImpl implements SeriesService { 21 | 22 | @Autowired 23 | private MongoOperations mongoOps; 24 | 25 | 26 | @Override 27 | public Series[] getAllSeries() { 28 | List seriesList = mongoOps.findAll(Series.class); 29 | return seriesList.toArray(new Series[0]); 30 | } 31 | 32 | @Override 33 | public Series getSeries(long id) { 34 | return mongoOps.findById(id, Series.class); 35 | } 36 | 37 | @Override 38 | public void insertSeries(Series series) { 39 | mongoOps.insert(series); 40 | } 41 | 42 | 43 | @Override 44 | public void deleteSeries(long id) { 45 | Query query = new Query(); 46 | Criteria criteria = new Criteria("_id").is(id); 47 | query.addCriteria(criteria); 48 | 49 | mongoOps.remove(query, Series.class); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/resources/xpadro/spring/web/configuration/app-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/resources/xpadro/spring/web/configuration/db-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/resources/xpadro/spring/web/configuration/root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Spring MVC - RESTful web services 7 | 8 | 9 | 10 | contextConfigLocation 11 | classpath:xpadro/spring/web/configuration/root-context.xml 12 | 13 | 14 | 15 | 16 | org.springframework.web.context.ContextLoaderListener 17 | 18 | 19 | 20 | 21 | springServlet 22 | org.springframework.web.servlet.DispatcherServlet 23 | 24 | contextConfigLocation 25 | classpath:xpadro/spring/web/configuration/app-context.xml 26 | 27 | 28 | 29 | springServlet 30 | /spring/* 31 | 32 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | 2 | 3 |

RESTful Web Services with Spring MVC

4 | 5 | 6 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/test/java/xpadro/spring/web/test/SeriesAsyncCallableFunctionalTest.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.test; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | import static org.junit.Assert.fail; 6 | 7 | import java.util.concurrent.ExecutionException; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.util.concurrent.ListenableFuture; 15 | import org.springframework.util.concurrent.ListenableFutureCallback; 16 | import org.springframework.web.client.AsyncRestTemplate; 17 | 18 | import xpadro.spring.web.model.Series; 19 | 20 | public class SeriesAsyncCallableFunctionalTest extends SeriesFunctionalBaseTests { 21 | private static final String BASE_URI = "http://localhost:8080/spring-rest-api-v4/spring/series"; 22 | private static Logger logger = LoggerFactory.getLogger(SeriesAsyncCallableFunctionalTest.class); 23 | 24 | private AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(); 25 | 26 | @Before 27 | public void setup() { 28 | initializeDatabase(); 29 | } 30 | 31 | 32 | @Test 33 | public void getAllSeriesAsyncCallable() throws InterruptedException, ExecutionException { 34 | logger.info("Calling async callable /series"); 35 | ListenableFuture> futureEntity = asyncRestTemplate.getForEntity(BASE_URI, Series[].class); 36 | futureEntity.addCallback(new ListenableFutureCallback>() { 37 | @Override 38 | public void onSuccess(ResponseEntity entity) { 39 | logger.info("Response received (async callable)"); 40 | Series[] series = entity.getBody(); 41 | validateList(series); 42 | } 43 | 44 | @Override 45 | public void onFailure(Throwable t) { 46 | fail(); 47 | } 48 | }); 49 | logger.info("Doing other async callable stuff ..."); 50 | Thread.sleep(6000); //waits for the service to send the response 51 | } 52 | 53 | private void validateList(Series[] series) { 54 | assertNotNull(series); 55 | assertEquals(2, series.length); 56 | assertEquals(1L, series[0].getId()); 57 | assertEquals("The walking dead", series[0].getName()); 58 | assertEquals("USA", series[0].getCountry()); 59 | assertEquals("Thriller", series[0].getGenre()); 60 | assertEquals(2L, series[1].getId()); 61 | assertEquals("Homeland", series[1].getName()); 62 | assertEquals("USA", series[1].getCountry()); 63 | assertEquals("Drama", series[1].getGenre()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/test/java/xpadro/spring/web/test/SeriesAsyncFunctionalTest.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.test; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.util.concurrent.ExecutionException; 7 | import java.util.concurrent.Future; 8 | 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.http.ResponseEntity; 14 | import org.springframework.web.client.AsyncRestTemplate; 15 | 16 | import xpadro.spring.web.model.Series; 17 | 18 | public class SeriesAsyncFunctionalTest extends SeriesFunctionalBaseTests { 19 | private static final String BASE_URI = "http://localhost:8080/spring-rest-api-v4/spring/series"; 20 | private static Logger logger = LoggerFactory.getLogger(SeriesAsyncFunctionalTest.class); 21 | 22 | private AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(); 23 | 24 | @Before 25 | public void setup() { 26 | initializeDatabase(); 27 | } 28 | 29 | 30 | @Test 31 | public void getAllSeriesAsync() throws InterruptedException, ExecutionException { 32 | logger.info("Calling async /series"); 33 | Future> futureEntity = asyncRestTemplate.getForEntity(BASE_URI, Series[].class); 34 | logger.info("Doing other async stuff..."); 35 | 36 | logger.info("Blocking to receive response..."); 37 | ResponseEntity entity = futureEntity.get(); 38 | logger.info("Response received"); 39 | Series[] series = entity.getBody(); 40 | 41 | assertNotNull(series); 42 | assertEquals(2, series.length); 43 | assertEquals(1L, series[0].getId()); 44 | assertEquals("The walking dead", series[0].getName()); 45 | assertEquals("USA", series[0].getCountry()); 46 | assertEquals("Thriller", series[0].getGenre()); 47 | assertEquals(2L, series[1].getId()); 48 | assertEquals("Homeland", series[1].getName()); 49 | assertEquals("USA", series[1].getCountry()); 50 | assertEquals("Drama", series[1].getGenre()); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/test/java/xpadro/spring/web/test/SeriesFunctionalBaseTests.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.test; 2 | 3 | import static org.junit.Assert.fail; 4 | 5 | import org.junit.runner.RunWith; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.dao.DataAccessResourceFailureException; 8 | import org.springframework.data.mongodb.core.MongoOperations; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | 12 | import xpadro.spring.web.model.Series; 13 | 14 | @RunWith(SpringJUnit4ClassRunner.class) 15 | @ContextConfiguration(locations={ 16 | "classpath:xpadro/spring/web/configuration/root-context.xml", 17 | "classpath:xpadro/spring/web/configuration/app-context.xml"}) 18 | public class SeriesFunctionalBaseTests { 19 | @Autowired 20 | private MongoOperations mongoOps; 21 | 22 | protected void initializeDatabase() { 23 | try { 24 | mongoOps.dropCollection("series"); 25 | 26 | mongoOps.insert(new Series(1, "The walking dead", "USA", "Thriller")); 27 | mongoOps.insert(new Series(2, "Homeland", "USA", "Drama")); 28 | } catch (DataAccessResourceFailureException e) { 29 | fail("MongoDB instance is not running"); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/test/java/xpadro/spring/web/test/SeriesFunctionalTest.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.test; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | import static org.junit.Assert.assertNotNull; 5 | 6 | import java.net.URI; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.junit.Before; 11 | import org.junit.Test; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.http.MediaType; 14 | import org.springframework.http.ResponseEntity; 15 | import org.springframework.http.converter.HttpMessageConverter; 16 | import org.springframework.http.converter.StringHttpMessageConverter; 17 | import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; 18 | import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; 19 | import org.springframework.web.client.HttpClientErrorException; 20 | import org.springframework.web.client.RestTemplate; 21 | 22 | import xpadro.spring.web.model.Series; 23 | 24 | public class SeriesFunctionalTest extends SeriesFunctionalBaseTests { 25 | private static final String BASE_URI = "http://localhost:8080/spring-rest-api-v4/spring/series"; 26 | private RestTemplate restTemplate = new RestTemplate(); 27 | 28 | @Before 29 | public void setup() { 30 | List> converters = new ArrayList>(); 31 | converters.add(new StringHttpMessageConverter()); 32 | converters.add(new Jaxb2RootElementHttpMessageConverter()); 33 | converters.add(new MappingJackson2HttpMessageConverter()); 34 | restTemplate.setMessageConverters(converters); 35 | 36 | initializeDatabase(); 37 | } 38 | 39 | 40 | @Test 41 | public void getAllSeries() { 42 | Series[] series = restTemplate.getForObject(BASE_URI, Series[].class); 43 | 44 | assertNotNull(series); 45 | assertEquals(2, series.length); 46 | assertEquals(1L, series[0].getId()); 47 | assertEquals("The walking dead", series[0].getName()); 48 | assertEquals("USA", series[0].getCountry()); 49 | assertEquals("Thriller", series[0].getGenre()); 50 | assertEquals(2L, series[1].getId()); 51 | assertEquals("Homeland", series[1].getName()); 52 | assertEquals("USA", series[1].getCountry()); 53 | assertEquals("Drama", series[1].getGenre()); 54 | } 55 | 56 | @Test 57 | public void getJsonSeries() { 58 | List> converters = new ArrayList>(); 59 | converters.add(new MappingJackson2HttpMessageConverter()); 60 | restTemplate.setMessageConverters(converters); 61 | 62 | String uri = BASE_URI + "/{seriesId}"; 63 | ResponseEntity seriesEntity = restTemplate.getForEntity(uri, Series.class, 1l); 64 | assertNotNull(seriesEntity.getBody()); 65 | assertEquals(1l, seriesEntity.getBody().getId()); 66 | assertEquals("The walking dead", seriesEntity.getBody().getName()); 67 | assertEquals("USA", seriesEntity.getBody().getCountry()); 68 | assertEquals("Thriller", seriesEntity.getBody().getGenre()); 69 | 70 | assertEquals(MediaType.parseMediaType("application/json;charset=UTF-8"), seriesEntity.getHeaders().getContentType()); 71 | } 72 | 73 | @Test 74 | public void getXmlSeries() { 75 | String uri = BASE_URI + "/{seriesId}"; 76 | ResponseEntity seriesEntity = restTemplate.getForEntity(uri, Series.class, 1L); 77 | assertNotNull(seriesEntity.getBody()); 78 | assertEquals(1l, seriesEntity.getBody().getId()); 79 | assertEquals("The walking dead", seriesEntity.getBody().getName()); 80 | assertEquals("USA", seriesEntity.getBody().getCountry()); 81 | assertEquals("Thriller", seriesEntity.getBody().getGenre()); 82 | 83 | assertEquals(MediaType.APPLICATION_XML, seriesEntity.getHeaders().getContentType()); 84 | } 85 | 86 | @Test 87 | public void getNotFoundSeries() { 88 | String uri = BASE_URI + "/{seriesId}"; 89 | 90 | try { 91 | restTemplate.getForEntity(uri, Series.class, 5L); 92 | } catch (HttpClientErrorException e) { 93 | assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode()); 94 | } 95 | } 96 | 97 | @Test 98 | public void insertNewSeries() { 99 | Series series = new Series(); 100 | series.setId(4L); 101 | series.setName("mySeries"); 102 | series.setCountry("England"); 103 | series.setGenre("sci-fi"); 104 | 105 | URI newUserLocation = restTemplate.postForLocation(BASE_URI, series); 106 | assertEquals(BASE_URI + "/4", newUserLocation.toString()); 107 | } 108 | 109 | @Test 110 | public void deleteExistingSeries() { 111 | String uri = BASE_URI + "/{seriesId}"; 112 | restTemplate.delete(uri, 2L); 113 | 114 | try { 115 | restTemplate.getForEntity(uri, Series.class, 2L); 116 | } catch (HttpClientErrorException e) { 117 | assertEquals(HttpStatus.NOT_FOUND, e.getStatusCode()); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/test/java/xpadro/spring/web/test/SeriesIntegrationTest.java: -------------------------------------------------------------------------------- 1 | package xpadro.spring.web.test; 2 | 3 | import static org.hamcrest.Matchers.hasSize; 4 | import static org.hamcrest.Matchers.is; 5 | import static org.hamcrest.Matchers.endsWith; 6 | import static org.mockito.Mockito.*; 7 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; 8 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; 9 | import org.springframework.test.context.ContextConfiguration; 10 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 11 | import org.springframework.test.context.web.WebAppConfiguration; 12 | import org.springframework.test.web.servlet.MockMvc; 13 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.junit.runner.RunWith; 17 | 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.web.context.WebApplicationContext; 20 | import org.springframework.http.MediaType; 21 | 22 | import xpadro.spring.web.model.Series; 23 | import xpadro.spring.web.service.SeriesService; 24 | 25 | @RunWith(SpringJUnit4ClassRunner.class) 26 | @WebAppConfiguration 27 | @ContextConfiguration(locations={ 28 | "classpath:xpadro/spring/web/test/configuration/test-root-context.xml", 29 | "classpath:xpadro/spring/web/configuration/app-context.xml"}) 30 | public class SeriesIntegrationTest { 31 | private static final String BASE_URI = "/series"; 32 | 33 | private MockMvc mockMvc; 34 | 35 | @Autowired 36 | private WebApplicationContext webApplicationContext; 37 | 38 | @Autowired 39 | private SeriesService seriesService; 40 | 41 | 42 | @Before 43 | public void setUp() { 44 | reset(seriesService); 45 | mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); 46 | 47 | when(seriesService.getAllSeries()).thenReturn(new Series[]{ 48 | new Series(1, "The walking dead", "USA", "Thriller"), 49 | new Series(2, "Homeland", "USA", "Drama")}); 50 | 51 | when(seriesService.getSeries(1L)).thenReturn(new Series(1, "Fringe", "USA", "Thriller")); 52 | } 53 | 54 | 55 | @Test 56 | public void getAllSeries() throws Exception { 57 | mockMvc.perform(get(BASE_URI) 58 | .accept(MediaType.APPLICATION_JSON)) 59 | .andExpect(status().isOk()) 60 | .andExpect(content().contentType("application/json;charset=UTF-8")) 61 | .andExpect(jsonPath("$", hasSize(2))) 62 | .andExpect(jsonPath("$[0].id", is(1))) 63 | .andExpect(jsonPath("$[0].name", is("The walking dead"))) 64 | .andExpect(jsonPath("$[0].country", is("USA"))) 65 | .andExpect(jsonPath("$[0].genre", is("Thriller"))) 66 | .andExpect(jsonPath("$[1].id", is(2))) 67 | .andExpect(jsonPath("$[1].name", is("Homeland"))) 68 | .andExpect(jsonPath("$[1].country", is("USA"))) 69 | .andExpect(jsonPath("$[1].genre", is("Drama"))); 70 | 71 | verify(seriesService, times(1)).getAllSeries(); 72 | verifyZeroInteractions(seriesService); 73 | } 74 | 75 | @Test 76 | public void getJsonSeries() throws Exception { 77 | mockMvc.perform(get(BASE_URI + "/{seriesId}", 1L) 78 | .accept(MediaType.APPLICATION_JSON)) 79 | .andExpect(status().isOk()) 80 | .andExpect(content().contentType("application/json;charset=UTF-8")) 81 | .andExpect(jsonPath("$.id", is(1))) 82 | .andExpect(jsonPath("$.name", is("Fringe"))) 83 | .andExpect(jsonPath("$.country", is("USA"))) 84 | .andExpect(jsonPath("$.genre", is("Thriller"))); 85 | 86 | verify(seriesService, times(1)).getSeries(1L); 87 | verifyZeroInteractions(seriesService); 88 | } 89 | 90 | @Test 91 | public void getXmlSeries() throws Exception { 92 | mockMvc.perform(get(BASE_URI + "/{seriesId}", 1L) 93 | .accept(MediaType.APPLICATION_XML)) 94 | .andExpect(status().isOk()) 95 | .andExpect(content().contentType(MediaType.APPLICATION_XML)) 96 | .andExpect(xpath("/series/id").string("1")) 97 | .andExpect(xpath("/series/name").string("Fringe")) 98 | .andExpect(xpath("/series/country").string("USA")) 99 | .andExpect(xpath("/series/genre").string("Thriller")); 100 | 101 | 102 | verify(seriesService, times(1)).getSeries(1L); 103 | verifyZeroInteractions(seriesService); 104 | } 105 | 106 | @Test 107 | public void getNotFoundSeries() throws Exception { 108 | mockMvc.perform(get(BASE_URI + "/{seriesId}", 5L) 109 | .accept(MediaType.APPLICATION_JSON)) 110 | .andExpect(status().isNotFound()); 111 | 112 | verify(seriesService, times(1)).getSeries(5L); 113 | verifyZeroInteractions(seriesService); 114 | } 115 | 116 | @Test 117 | public void insertNewSeries() throws Exception { 118 | mockMvc.perform(post(BASE_URI) 119 | .content("{ \"id\": 3, \"name\": \"mySeries\", \"country\": \"England\", \"genre\": \"sci-fi\" } }") 120 | .contentType(MediaType.APPLICATION_JSON) 121 | .accept(MediaType.APPLICATION_JSON)) 122 | .andExpect(status().isCreated()) 123 | .andExpect(header().string("Location", endsWith("/series/3"))); 124 | 125 | verify(seriesService, times(1)).insertSeries(any(Series.class)); 126 | verifyZeroInteractions(seriesService); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /spring-rest-api-v4/src/test/resources/xpadro/spring/web/test/configuration/test-root-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | --------------------------------------------------------------------------------