From aa1397b8ba73d993d213b87b5a7f17d0fcf8776e Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 11 Jul 2016 13:56:00 -0400 Subject: [PATCH 1/5] Polish method order in RequestMappingIntegrationTests --- .../RequestMappingIntegrationTests.java | 215 +++++++++--------- 1 file changed, 109 insertions(+), 106 deletions(-) diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java index d3a3e839d2c..2126fe14690 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java @@ -128,24 +128,6 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati assertEquals(expected, performGet("/raw-observable", null, String.class).getBody()); } - @Test - public void handleWithThrownException() throws Exception { - String expected = "Recovered from error: Boo"; - assertEquals(expected, performGet("/thrown-exception", null, String.class).getBody()); - } - - @Test - public void handleWithErrorSignal() throws Exception { - String expected = "Recovered from error: Boo"; - assertEquals(expected, performGet("/error-signal", null, String.class).getBody()); - } - - @Test - public void streamResult() throws Exception { - String[] expected = {"0", "1", "2", "3", "4"}; - assertArrayEquals(expected, performGet("/stream-result", null, String[].class).getBody()); - } - @Test public void serializeAsPojo() throws Exception { Person expected = new Person("Robert"); @@ -158,12 +140,6 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati assertEquals(expected, performGet("/completable-future", JSON, Person.class).getBody()); } - @Test - public void serializeAsMonoResponseEntity() throws Exception { - Person expected = new Person("Robert"); - assertEquals(expected, performGet("/monoResponseEntity", JSON, Person.class).getBody()); - } - @Test public void serializeAsMono() throws Exception { Person expected = new Person("Robert"); @@ -176,6 +152,12 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati assertEquals(expected, performGet("/single", JSON, Person.class).getBody()); } + @Test + public void serializeAsMonoResponseEntity() throws Exception { + Person expected = new Person("Robert"); + assertEquals(expected, performGet("/monoResponseEntity", JSON, Person.class).getBody()); + } + @Test public void serializeAsList() throws Exception { List expected = asList(new Person("Robert"), new Person("Marie")); @@ -201,30 +183,14 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati } @Test - public void serializeAsReactorStream() throws Exception { - List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/stream", JSON, PERSON_LIST).getBody()); - } - - @Test - public void publisherCapitalize() throws Exception { - List req = asList(new Person("Robert"), new Person("Marie")); - List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/publisher-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); - } - - @Test - public void fluxCapitalize() throws Exception { - List req = asList(new Person("Robert"), new Person("Marie")); - List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/flux-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); - } + public void resource() throws Exception { + ResponseEntity response = performGet("/resource", null, byte[].class); - @Test - public void observableCapitalize() throws Exception { - List req = asList(new Person("Robert"), new Person("Marie")); - List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/observable-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertTrue(response.hasBody()); + assertEquals(951, response.getHeaders().getContentLength()); + assertEquals(951, response.getBody().length); + assertEquals(new MediaType("image", "x-png"), response.getHeaders().getContentType()); } @Test @@ -233,7 +199,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati performPost("/person-capitalize", JSON, new Person("Robert"), JSON, Person.class).getBody()); } - + @Test public void completableFutureCapitalize() throws Exception { assertEquals(new Person("ROBERT"), @@ -255,6 +221,27 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati JSON, Person.class).getBody()); } + @Test + public void publisherCapitalize() throws Exception { + List req = asList(new Person("Robert"), new Person("Marie")); + List res = asList(new Person("ROBERT"), new Person("MARIE")); + assertEquals(res, performPost("/publisher-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + } + + @Test + public void fluxCapitalize() throws Exception { + List req = asList(new Person("Robert"), new Person("Marie")); + List res = asList(new Person("ROBERT"), new Person("MARIE")); + assertEquals(res, performPost("/flux-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + } + + @Test + public void observableCapitalize() throws Exception { + List req = asList(new Person("Robert"), new Person("Marie")); + List res = asList(new Person("ROBERT"), new Person("MARIE")); + assertEquals(res, performPost("/observable-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + } + @Test public void publisherCreate() throws Exception { ResponseEntity entity = performPost("/publisher-create", JSON, @@ -310,20 +297,27 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati } @Test - public void html() throws Exception { - String expected = "Hello: Jason!"; - assertEquals(expected, performGet("/html?name=Jason", MediaType.TEXT_HTML, String.class).getBody()); + public void streamResult() throws Exception { + String[] expected = {"0", "1", "2", "3", "4"}; + assertArrayEquals(expected, performGet("/stream-result", null, String[].class).getBody()); } @Test - public void resource() throws Exception { - ResponseEntity response = performGet("/resource", null, byte[].class); + public void handleWithThrownException() throws Exception { + String expected = "Recovered from error: Boo"; + assertEquals(expected, performGet("/thrown-exception", null, String.class).getBody()); + } - assertEquals(HttpStatus.OK, response.getStatusCode()); - assertTrue(response.hasBody()); - assertEquals(951, response.getHeaders().getContentLength()); - assertEquals(951, response.getBody().length); - assertEquals(new MediaType("image", "x-png"), response.getHeaders().getContentType()); + @Test + public void handleWithErrorSignal() throws Exception { + String expected = "Recovered from error: Boo"; + assertEquals(expected, performGet("/error-signal", null, String.class).getBody()); + } + + @Test + public void html() throws Exception { + String expected = "Hello: Jason!"; + assertEquals(expected, performGet("/html?name=Jason", MediaType.TEXT_HTML, String.class).getBody()); } @@ -410,15 +404,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati return Flux.just("Hello ", name, "!"); } - @RequestMapping("/person") - public Person personResponseBody() { - return new Person("Robert"); - } - - @RequestMapping("/completable-future") - public CompletableFuture completableFutureResponseBody() { - return CompletableFuture.completedFuture(new Person("Robert")); - } + // Response body with "raw" data (DataBuffer) @RequestMapping("/raw") public Publisher rawResponseBody() { @@ -428,11 +414,6 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati ResolvableType.forClass(Person.class), JSON).map(DataBuffer::asByteBuffer); } - @RequestMapping("/stream-result") - public Publisher stringStreamResponseBody() { - return Flux.interval(100).take(5); - } - @RequestMapping("/raw-flux") public Flux rawFluxResponseBody() { return Flux.just(ByteBuffer.wrap("Hello!".getBytes())); @@ -443,10 +424,16 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati return Observable.just(ByteBuffer.wrap("Hello!".getBytes())); } - @RequestMapping("/monoResponseEntity") - public ResponseEntity> monoResponseEntity() { - Mono body = Mono.just(new Person("Robert")); - return ResponseEntity.ok(body); + // Response body with Person Object(s) to "serialize" + + @RequestMapping("/person") + public Person personResponseBody() { + return new Person("Robert"); + } + + @RequestMapping("/completable-future") + public CompletableFuture completableFutureResponseBody() { + return CompletableFuture.completedFuture(new Person("Robert")); } @RequestMapping("/mono") @@ -459,6 +446,12 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati return Single.just(new Person("Robert")); } + @RequestMapping("/monoResponseEntity") + public ResponseEntity> monoResponseEntity() { + Mono body = Mono.just(new Person("Robert")); + return ResponseEntity.ok(body); + } + @RequestMapping("/list") public List listResponseBody() { return asList(new Person("Robert"), new Person("Marie")); @@ -479,38 +472,21 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati return Observable.just(new Person("Robert"), new Person("Marie")); } - @RequestMapping("/stream") - public Flux reactorStreamResponseBody() { - return Flux.just(new Person("Robert"), new Person("Marie")); - } - - @RequestMapping("/publisher-capitalize") - public Publisher publisherCapitalize(@RequestBody Publisher persons) { - return Flux - .from(persons) - .map(person -> new Person(person.getName().toUpperCase())); - } + // ResponseBody with Resource - @RequestMapping("/flux-capitalize") - public Flux fluxCapitalize(@RequestBody Flux persons) { - return persons.map(person -> new Person(person.getName().toUpperCase())); - } - - @RequestMapping("/observable-capitalize") - public Observable observableCapitalize(@RequestBody Observable persons) { - return persons.map(person -> new Person(person.getName().toUpperCase())); + @RequestMapping("/resource") + @ResponseBody + public Resource resource() { + return new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class); } - @RequestMapping("/stream-create") - public Publisher streamCreate(@RequestBody Flux personStream) { - return personStream.collectList().doOnSuccess(persons::addAll).then(); - } + // RequestBody -> ResponseBody with Person "capitalize" name transformation @RequestMapping("/person-capitalize") public Person personCapitalize(@RequestBody Person person) { return new Person(person.getName().toUpperCase()); } - + @RequestMapping("/completable-future-capitalize") public CompletableFuture completableFutureCapitalize( @RequestBody CompletableFuture personFuture) { @@ -527,6 +503,30 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati return personFuture.map(person -> new Person(person.getName().toUpperCase())); } + @RequestMapping("/publisher-capitalize") + public Publisher publisherCapitalize(@RequestBody Publisher persons) { + return Flux + .from(persons) + .map(person -> new Person(person.getName().toUpperCase())); + } + + @RequestMapping("/flux-capitalize") + public Flux fluxCapitalize(@RequestBody Flux persons) { + return persons.map(person -> new Person(person.getName().toUpperCase())); + } + + @RequestMapping("/observable-capitalize") + public Observable observableCapitalize(@RequestBody Observable persons) { + return persons.map(person -> new Person(person.getName().toUpperCase())); + } + + // Request body with Objects to "create" + + @RequestMapping("/stream-create") + public Publisher streamCreate(@RequestBody Flux personStream) { + return personStream.collectList().doOnSuccess(persons::addAll).then(); + } + @RequestMapping("/publisher-create") public Publisher publisherCreate(@RequestBody Publisher personStream) { return Flux.from(personStream).doOnNext(persons::add).then(); @@ -542,6 +542,15 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati return personStream.toList().doOnNext(persons::addAll).flatMap(document -> Observable.empty()); } + // Async stream + + @RequestMapping("/stream-result") + public Publisher stringStreamResponseBody() { + return Flux.interval(100).take(5); + } + + // Error handling + @RequestMapping("/thrown-exception") public Publisher handleAndThrowException() { throw new IllegalStateException("Boo"); @@ -557,12 +566,6 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati return Mono.just("Recovered from error: " + ex.getMessage()); } - @RequestMapping("/resource") - @ResponseBody - public Resource resource() { - return new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class); - } - //TODO add mixed and T request mappings tests } From 6fde86903d1bffaeb2259505ac626106a1e5019c Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 11 Jul 2016 14:07:12 -0400 Subject: [PATCH 2/5] Declare HTTP method mappings TestRestController --- .../RequestMappingIntegrationTests.java | 73 +++++++++---------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java index 2126fe14690..069ece27dac 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java @@ -53,10 +53,10 @@ import org.springframework.http.server.reactive.ZeroCopyIntegrationTests; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.springframework.web.reactive.DispatcherHandler; @@ -399,14 +399,14 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati final List persons = new ArrayList<>(); - @RequestMapping("/param") + @GetMapping("/param") public Publisher handleWithParam(@RequestParam String name) { return Flux.just("Hello ", name, "!"); } - // Response body with "raw" data (DataBuffer) + // GET with "raw" data (DataBuffer) response body - @RequestMapping("/raw") + @GetMapping("/raw") public Publisher rawResponseBody() { DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); JacksonJsonEncoder encoder = new JacksonJsonEncoder(); @@ -414,149 +414,148 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati ResolvableType.forClass(Person.class), JSON).map(DataBuffer::asByteBuffer); } - @RequestMapping("/raw-flux") + @GetMapping("/raw-flux") public Flux rawFluxResponseBody() { return Flux.just(ByteBuffer.wrap("Hello!".getBytes())); } - @RequestMapping("/raw-observable") + @GetMapping("/raw-observable") public Observable rawObservableResponseBody() { return Observable.just(ByteBuffer.wrap("Hello!".getBytes())); } - // Response body with Person Object(s) to "serialize" + // GET with Person Object(s) response body to "serialize" - @RequestMapping("/person") + @GetMapping("/person") public Person personResponseBody() { return new Person("Robert"); } - @RequestMapping("/completable-future") + @GetMapping("/completable-future") public CompletableFuture completableFutureResponseBody() { return CompletableFuture.completedFuture(new Person("Robert")); } - @RequestMapping("/mono") + @GetMapping("/mono") public Mono monoResponseBody() { return Mono.just(new Person("Robert")); } - @RequestMapping("/single") + @GetMapping("/single") public Single singleResponseBody() { return Single.just(new Person("Robert")); } - @RequestMapping("/monoResponseEntity") + @GetMapping("/monoResponseEntity") public ResponseEntity> monoResponseEntity() { Mono body = Mono.just(new Person("Robert")); return ResponseEntity.ok(body); } - @RequestMapping("/list") + @GetMapping("/list") public List listResponseBody() { return asList(new Person("Robert"), new Person("Marie")); } - @RequestMapping("/publisher") + @GetMapping("/publisher") public Publisher publisherResponseBody() { return Flux.just(new Person("Robert"), new Person("Marie")); } - @RequestMapping("/flux") + @GetMapping("/flux") public Flux fluxResponseBody() { return Flux.just(new Person("Robert"), new Person("Marie")); } - @RequestMapping("/observable") + @GetMapping("/observable") public Observable observableResponseBody() { return Observable.just(new Person("Robert"), new Person("Marie")); } - // ResponseBody with Resource + // GET with Resource response body - @RequestMapping("/resource") - @ResponseBody + @GetMapping("/resource") public Resource resource() { return new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class); } - // RequestBody -> ResponseBody with Person "capitalize" name transformation + // POST with Person "capitalize" name transformation - @RequestMapping("/person-capitalize") + @PostMapping("/person-capitalize") public Person personCapitalize(@RequestBody Person person) { return new Person(person.getName().toUpperCase()); } - @RequestMapping("/completable-future-capitalize") + @PostMapping("/completable-future-capitalize") public CompletableFuture completableFutureCapitalize( @RequestBody CompletableFuture personFuture) { return personFuture.thenApply(person -> new Person(person.getName().toUpperCase())); } - @RequestMapping("/mono-capitalize") + @PostMapping("/mono-capitalize") public Mono monoCapitalize(@RequestBody Mono personFuture) { return personFuture.map(person -> new Person(person.getName().toUpperCase())); } - @RequestMapping("/single-capitalize") + @PostMapping("/single-capitalize") public Single singleCapitalize(@RequestBody Single personFuture) { return personFuture.map(person -> new Person(person.getName().toUpperCase())); } - @RequestMapping("/publisher-capitalize") + @PostMapping("/publisher-capitalize") public Publisher publisherCapitalize(@RequestBody Publisher persons) { return Flux .from(persons) .map(person -> new Person(person.getName().toUpperCase())); } - @RequestMapping("/flux-capitalize") + @PostMapping("/flux-capitalize") public Flux fluxCapitalize(@RequestBody Flux persons) { return persons.map(person -> new Person(person.getName().toUpperCase())); } - @RequestMapping("/observable-capitalize") + @PostMapping("/observable-capitalize") public Observable observableCapitalize(@RequestBody Observable persons) { return persons.map(person -> new Person(person.getName().toUpperCase())); } - // Request body with Objects to "create" + // POST with Objects to "create" - @RequestMapping("/stream-create") + @PostMapping("/stream-create") public Publisher streamCreate(@RequestBody Flux personStream) { return personStream.collectList().doOnSuccess(persons::addAll).then(); } - @RequestMapping("/publisher-create") + @PostMapping("/publisher-create") public Publisher publisherCreate(@RequestBody Publisher personStream) { return Flux.from(personStream).doOnNext(persons::add).then(); } - @RequestMapping("/flux-create") + @PostMapping("/flux-create") public Mono fluxCreate(@RequestBody Flux personStream) { return personStream.doOnNext(persons::add).then(); } - @RequestMapping("/observable-create") + @PostMapping("/observable-create") public Observable observableCreate(@RequestBody Observable personStream) { return personStream.toList().doOnNext(persons::addAll).flatMap(document -> Observable.empty()); } // Async stream - @RequestMapping("/stream-result") + @GetMapping("/stream-result") public Publisher stringStreamResponseBody() { return Flux.interval(100).take(5); } // Error handling - @RequestMapping("/thrown-exception") + @GetMapping("/thrown-exception") public Publisher handleAndThrowException() { throw new IllegalStateException("Boo"); } - @RequestMapping("/error-signal") + @GetMapping("/error-signal") public Publisher handleWithError() { return Mono.error(new IllegalStateException("Boo")); } @@ -574,7 +573,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati @SuppressWarnings("unused") private static class TestController { - @RequestMapping("/html") + @GetMapping("/html") public String getHtmlPage(@RequestParam String name, Model model) { model.addAttribute("hello", "Hello: " + name + "!"); return "test"; From 35f791acf8a89ab017b25ed98596d4366cd76ca0 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 11 Jul 2016 14:41:15 -0400 Subject: [PATCH 3/5] Extract base class for RequestMappingIntegrationTests --- ...bstractRequestMappingIntegrationTests.java | 95 +++++++++++++++++++ .../RequestMappingIntegrationTests.java | 71 +++----------- 2 files changed, 108 insertions(+), 58 deletions(-) create mode 100644 spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java new file mode 100644 index 00000000000..2beb97217fe --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/AbstractRequestMappingIntegrationTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.web.reactive.result.method.annotation; + +import java.net.URI; + +import org.springframework.context.ApplicationContext; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.http.server.reactive.AbstractHttpHandlerIntegrationTests; +import org.springframework.http.server.reactive.HttpHandler; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.reactive.DispatcherHandler; +import org.springframework.web.server.adapter.WebHttpHandlerBuilder; + +import static org.springframework.http.RequestEntity.get; + +/** + * + * @author Rossen Stoyanchev + */ +public abstract class AbstractRequestMappingIntegrationTests extends AbstractHttpHandlerIntegrationTests { + + private ApplicationContext applicationContext; + + private RestTemplate restTemplate = new RestTemplate(); + + + @Override + protected HttpHandler createHttpHandler() { + this.applicationContext = initApplicationContext(); + DispatcherHandler handler = new DispatcherHandler(); + handler.setApplicationContext(this.applicationContext); + return WebHttpHandlerBuilder.webHandler(handler).build(); + } + + protected abstract ApplicationContext initApplicationContext(); + + + ApplicationContext getApplicationContext() { + return this.applicationContext; + } + + + ResponseEntity performGet(String url, MediaType out, + Class type) throws Exception { + + return this.restTemplate.exchange(prepareGet(url, out), type); + } + + ResponseEntity performGet(String url, MediaType out, + ParameterizedTypeReference type) throws Exception { + + return this.restTemplate.exchange(prepareGet(url, out), type); + } + + ResponseEntity performPost(String url, MediaType in, Object body, MediaType out, + Class type) throws Exception { + + return this.restTemplate.exchange(preparePost(url, in, body, out), type); + } + + ResponseEntity performPost(String url, MediaType in, Object body, + MediaType out, ParameterizedTypeReference type) throws Exception { + + return this.restTemplate.exchange(preparePost(url, in, body, out), type); + } + + private RequestEntity prepareGet(String url, MediaType accept) throws Exception { + URI uri = new URI("http://localhost:" + this.port + url); + return (accept != null ? get(uri).accept(accept).build() : get(uri).build()); + } + + private RequestEntity preparePost(String url, MediaType in, Object body, MediaType out) throws Exception { + URI uri = new URI("http://localhost:" + this.port + url); + return (out != null ? + RequestEntity.post(uri).contentType(in).accept(out).body(body) : + RequestEntity.post(uri).contentType(in).body(body)); + } +} diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java index 069ece27dac..61aa66e6084 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java @@ -32,6 +32,7 @@ import reactor.core.publisher.Mono; import rx.Observable; import rx.Single; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -79,7 +80,7 @@ import static org.springframework.http.RequestEntity.get; * @author Sebastien Deleuze * @author Stephane Maldini */ -public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrationTests { +public class RequestMappingIntegrationTests extends AbstractRequestMappingIntegrationTests { private static final ParameterizedTypeReference> PERSON_LIST = new ParameterizedTypeReference>() {}; @@ -87,21 +88,12 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati private static final MediaType JSON = MediaType.APPLICATION_JSON; - private AnnotationConfigApplicationContext wac; - - private RestTemplate restTemplate = new RestTemplate(); - - @Override - protected HttpHandler createHttpHandler() { - this.wac = new AnnotationConfigApplicationContext(); - this.wac.register(FrameworkConfig.class, ApplicationConfig.class); - this.wac.refresh(); - - DispatcherHandler handler = new DispatcherHandler(); - handler.setApplicationContext(this.wac); - - return WebHttpHandlerBuilder.webHandler(handler).build(); + protected ApplicationContext initApplicationContext() { + AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext(); + wac.register(FrameworkConfig.class, ApplicationConfig.class); + wac.refresh(); + return wac; } @Test @@ -248,7 +240,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati asList(new Person("Robert"), new Person("Marie")), null, Void.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, this.wac.getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); } @Test @@ -257,7 +249,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati ResponseEntity response = performPost("/publisher-create", APPLICATION_XML, people, null, Void.class); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, this.wac.getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); } @Test @@ -266,7 +258,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati asList(new Person("Robert"), new Person("Marie")), null, Void.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, this.wac.getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); } @Test @@ -275,7 +267,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati ResponseEntity response = performPost("/flux-create", APPLICATION_XML, people, null, Void.class); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, this.wac.getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); } @Test @@ -284,7 +276,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati asList(new Person("Robert"), new Person("Marie")), null, Void.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, this.wac.getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); } @Test @@ -293,7 +285,7 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati ResponseEntity response = performPost("/observable-create", APPLICATION_XML, people, null, Void.class); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, this.wac.getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); } @Test @@ -321,43 +313,6 @@ public class RequestMappingIntegrationTests extends AbstractHttpHandlerIntegrati } - private ResponseEntity performGet(String url, MediaType acceptHeader, - Class type) throws Exception { - - return this.restTemplate.exchange(prepareGet(url, acceptHeader), type); - } - - private ResponseEntity performGet(String url, MediaType acceptHeader, - ParameterizedTypeReference type) throws Exception { - - return this.restTemplate.exchange(prepareGet(url, acceptHeader), type); - } - - private ResponseEntity performPost(String url, MediaType in, Object body, - MediaType out, Class type) throws Exception { - - return this.restTemplate.exchange(preparePost(url, in, body, out), type); - } - - private ResponseEntity performPost(String url, MediaType in, Object body, - MediaType out, ParameterizedTypeReference type) throws Exception { - - return this.restTemplate.exchange(preparePost(url, in, body, out), type); - } - - private RequestEntity prepareGet(String url, MediaType accept) throws Exception { - URI uri = new URI("http://localhost:" + this.port + url); - return (accept != null ? get(uri).accept(accept).build() : get(uri).build()); - } - - private RequestEntity preparePost(String url, MediaType in, Object body, MediaType out) throws Exception { - URI uri = new URI("http://localhost:" + this.port + url); - return (out != null ? - RequestEntity.post(uri).contentType(in).accept(out).body(body) : - RequestEntity.post(uri).contentType(in).body(body)); - } - - @Configuration @SuppressWarnings({"unused", "WeakerAccess"}) static class FrameworkConfig extends WebReactiveConfiguration { From 7e07fb16d8762c7e1fbd205a8bb44d366938bfe7 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 11 Jul 2016 16:45:18 -0400 Subject: [PATCH 4/5] Split RequestMappingIntegrationTests into sub-classes --- ...pingExceptionHandlingIntegrationTests.java | 94 ++++ .../RequestMappingIntegrationTests.java | 532 +----------------- ...pingMessageConversionIntegrationTests.java | 489 ++++++++++++++++ ...MappingViewResolutionIntegrationTests.java | 93 +++ 4 files changed, 685 insertions(+), 523 deletions(-) create mode 100644 spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingExceptionHandlingIntegrationTests.java create mode 100644 spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java create mode 100644 spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingViewResolutionIntegrationTests.java diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingExceptionHandlingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingExceptionHandlingIntegrationTests.java new file mode 100644 index 00000000000..c11d2d6ded6 --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingExceptionHandlingIntegrationTests.java @@ -0,0 +1,94 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.reactive.result.method.annotation; + +import org.junit.Test; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.config.WebReactiveConfiguration; + +import static org.junit.Assert.assertEquals; + + +/** + * {@code @RequestMapping} integration tests with exception handling scenarios. + * + * @author Rossen Stoyanchev + */ +public class RequestMappingExceptionHandlingIntegrationTests extends AbstractRequestMappingIntegrationTests { + + + @Override + protected ApplicationContext initApplicationContext() { + AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext(); + wac.register(WebConfig.class); + wac.refresh(); + return wac; + } + + + @Test + public void controllerThrowingException() throws Exception { + String expected = "Recovered from error: Boo"; + assertEquals(expected, performGet("/thrown-exception", null, String.class).getBody()); + } + + @Test + public void controllerReturnsMonoError() throws Exception { + String expected = "Recovered from error: Boo"; + assertEquals(expected, performGet("/mono-error", null, String.class).getBody()); + } + + + @Configuration + @ComponentScan(resourcePattern = "**/RequestMappingExceptionHandlingIntegrationTests$*.class") + @SuppressWarnings({"unused", "WeakerAccess"}) + static class WebConfig extends WebReactiveConfiguration { + + } + + + @RestController + @SuppressWarnings("unused") + private static class TestController { + + @GetMapping("/thrown-exception") + public Publisher handleAndThrowException() { + throw new IllegalStateException("Boo"); + } + + @GetMapping("/mono-error") + public Publisher handleWithError() { + return Mono.error(new IllegalStateException("Boo")); + } + + @ExceptionHandler + public Publisher handleException(IllegalStateException ex) { + return Mono.just("Recovered from error: " + ex.getMessage()); + } + + } + +} diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java index 61aa66e6084..3b5a3323190 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingIntegrationTests.java @@ -16,82 +16,38 @@ package org.springframework.web.reactive.result.method.annotation; -import java.net.URI; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.CompletableFuture; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; - import org.junit.Test; import org.reactivestreams.Publisher; import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import rx.Observable; -import rx.Single; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; -import org.springframework.core.ParameterizedTypeReference; -import org.springframework.core.ResolvableType; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.core.io.buffer.DataBufferFactory; -import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.MediaType; -import org.springframework.http.RequestEntity; -import org.springframework.http.ResponseEntity; -import org.springframework.http.codec.json.JacksonJsonEncoder; -import org.springframework.http.server.reactive.AbstractHttpHandlerIntegrationTests; -import org.springframework.http.server.reactive.HttpHandler; -import org.springframework.http.server.reactive.ZeroCopyIntegrationTests; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; -import org.springframework.web.reactive.DispatcherHandler; -import org.springframework.web.reactive.config.ViewResolverRegistry; import org.springframework.web.reactive.config.WebReactiveConfiguration; -import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer; -import org.springframework.web.server.adapter.WebHttpHandlerBuilder; -import static java.util.Arrays.asList; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.springframework.http.MediaType.APPLICATION_XML; -import static org.springframework.http.RequestEntity.get; /** - * Integration tests with {@code @RequestMapping} methods. + * Integration tests with {@code @RequestMapping} handler methods. + * + *

Before adding tests here consider if they are a better fit for any of the + * other {@code RequestMapping*IntegrationTests}. + * * @author Rossen Stoyanchev - * @author Sebastien Deleuze * @author Stephane Maldini */ public class RequestMappingIntegrationTests extends AbstractRequestMappingIntegrationTests { - private static final ParameterizedTypeReference> PERSON_LIST = - new ParameterizedTypeReference>() {}; - - private static final MediaType JSON = MediaType.APPLICATION_JSON; - - @Override protected ApplicationContext initApplicationContext() { AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext(); - wac.register(FrameworkConfig.class, ApplicationConfig.class); + wac.register(WebConfig.class); wac.refresh(); return wac; } @@ -102,503 +58,33 @@ public class RequestMappingIntegrationTests extends AbstractRequestMappingIntegr assertEquals(expected, performGet("/param?name=George", null, String.class).getBody()); } - @Test - public void rawPojoResponse() throws Exception { - Person expected = new Person("Robert"); - assertEquals(expected, performGet("/raw", JSON, Person.class).getBody()); - } - - @Test - public void rawFluxResponse() throws Exception { - String expected = "Hello!"; - assertEquals(expected, performGet("/raw-flux", null, String.class).getBody()); - } - - @Test - public void rawObservableResponse() throws Exception { - String expected = "Hello!"; - assertEquals(expected, performGet("/raw-observable", null, String.class).getBody()); - } - - @Test - public void serializeAsPojo() throws Exception { - Person expected = new Person("Robert"); - assertEquals(expected, performGet("/person", JSON, Person.class).getBody()); - } - - @Test - public void serializeAsCompletableFuture() throws Exception { - Person expected = new Person("Robert"); - assertEquals(expected, performGet("/completable-future", JSON, Person.class).getBody()); - } - - @Test - public void serializeAsMono() throws Exception { - Person expected = new Person("Robert"); - assertEquals(expected, performGet("/mono", JSON, Person.class).getBody()); - } - - @Test - public void serializeAsSingle() throws Exception { - Person expected = new Person("Robert"); - assertEquals(expected, performGet("/single", JSON, Person.class).getBody()); - } - - @Test - public void serializeAsMonoResponseEntity() throws Exception { - Person expected = new Person("Robert"); - assertEquals(expected, performGet("/monoResponseEntity", JSON, Person.class).getBody()); - } - - @Test - public void serializeAsList() throws Exception { - List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/list", JSON, PERSON_LIST).getBody()); - } - - @Test - public void serializeAsPublisher() throws Exception { - List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/publisher", JSON, PERSON_LIST).getBody()); - } - - @Test - public void serializeAsFlux() throws Exception { - List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/flux", JSON, PERSON_LIST).getBody()); - } - - @Test - public void serializeAsObservable() throws Exception { - List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/observable", JSON, PERSON_LIST).getBody()); - } - - @Test - public void resource() throws Exception { - ResponseEntity response = performGet("/resource", null, byte[].class); - - assertEquals(HttpStatus.OK, response.getStatusCode()); - assertTrue(response.hasBody()); - assertEquals(951, response.getHeaders().getContentLength()); - assertEquals(951, response.getBody().length); - assertEquals(new MediaType("image", "x-png"), response.getHeaders().getContentType()); - } - - @Test - public void personCapitalize() throws Exception { - assertEquals(new Person("ROBERT"), - performPost("/person-capitalize", JSON, new Person("Robert"), - JSON, Person.class).getBody()); - } - - @Test - public void completableFutureCapitalize() throws Exception { - assertEquals(new Person("ROBERT"), - performPost("/completable-future-capitalize", JSON, new Person("Robert"), - JSON, Person.class).getBody()); - } - - @Test - public void monoCapitalize() throws Exception { - assertEquals(new Person("ROBERT"), - performPost("/mono-capitalize", JSON, new Person("Robert"), - JSON, Person.class).getBody()); - } - - @Test - public void singleCapitalize() throws Exception { - assertEquals(new Person("ROBERT"), - performPost("/single-capitalize", JSON, new Person("Robert"), - JSON, Person.class).getBody()); - } - - @Test - public void publisherCapitalize() throws Exception { - List req = asList(new Person("Robert"), new Person("Marie")); - List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/publisher-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); - } - - @Test - public void fluxCapitalize() throws Exception { - List req = asList(new Person("Robert"), new Person("Marie")); - List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/flux-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); - } - - @Test - public void observableCapitalize() throws Exception { - List req = asList(new Person("Robert"), new Person("Marie")); - List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/observable-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); - } - - @Test - public void publisherCreate() throws Exception { - ResponseEntity entity = performPost("/publisher-create", JSON, - asList(new Person("Robert"), new Person("Marie")), null, Void.class); - - assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); - } - - @Test - public void publisherCreateXml() throws Exception { - People people = new People(new Person("Robert"), new Person("Marie")); - ResponseEntity response = performPost("/publisher-create", APPLICATION_XML, people, null, Void.class); - - assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); - } - - @Test - public void fluxCreate() throws Exception { - ResponseEntity entity = performPost("/flux-create", JSON, - asList(new Person("Robert"), new Person("Marie")), null, Void.class); - - assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); - } - - @Test - public void fluxCreateXml() throws Exception { - People people = new People(new Person("Robert"), new Person("Marie")); - ResponseEntity response = performPost("/flux-create", APPLICATION_XML, people, null, Void.class); - - assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); - } - - @Test - public void observableCreate() throws Exception { - ResponseEntity entity = performPost("/observable-create", JSON, - asList(new Person("Robert"), new Person("Marie")), null, Void.class); - - assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); - } - - @Test - public void observableCreateXml() throws Exception { - People people = new People(new Person("Robert"), new Person("Marie")); - ResponseEntity response = performPost("/observable-create", APPLICATION_XML, people, null, Void.class); - - assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); - } - @Test public void streamResult() throws Exception { String[] expected = {"0", "1", "2", "3", "4"}; assertArrayEquals(expected, performGet("/stream-result", null, String[].class).getBody()); } - @Test - public void handleWithThrownException() throws Exception { - String expected = "Recovered from error: Boo"; - assertEquals(expected, performGet("/thrown-exception", null, String.class).getBody()); - } - - @Test - public void handleWithErrorSignal() throws Exception { - String expected = "Recovered from error: Boo"; - assertEquals(expected, performGet("/error-signal", null, String.class).getBody()); - } - - @Test - public void html() throws Exception { - String expected = "Hello: Jason!"; - assertEquals(expected, performGet("/html?name=Jason", MediaType.TEXT_HTML, String.class).getBody()); - } - - - @Configuration - @SuppressWarnings({"unused", "WeakerAccess"}) - static class FrameworkConfig extends WebReactiveConfiguration { - - @Override - protected void configureViewResolvers(ViewResolverRegistry registry) { - registry.freeMarker(); - } - - @Bean - public FreeMarkerConfigurer freeMarkerConfig() { - FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); - configurer.setPreferFileSystemAccess(false); - configurer.setTemplateLoaderPath("classpath*:org/springframework/web/reactive/view/freemarker/"); - return configurer; - } - - } @Configuration + @ComponentScan(resourcePattern = "**/RequestMappingIntegrationTests$*.class") @SuppressWarnings({"unused", "WeakerAccess"}) - static class ApplicationConfig { - - @Bean - public TestRestController testRestController() { - return new TestRestController(); - } - - @Bean - public TestController testController() { - return new TestController(); - } + static class WebConfig extends WebReactiveConfiguration { } - @RestController @SuppressWarnings("unused") private static class TestRestController { - final List persons = new ArrayList<>(); - @GetMapping("/param") public Publisher handleWithParam(@RequestParam String name) { return Flux.just("Hello ", name, "!"); } - // GET with "raw" data (DataBuffer) response body - - @GetMapping("/raw") - public Publisher rawResponseBody() { - DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); - JacksonJsonEncoder encoder = new JacksonJsonEncoder(); - return encoder.encode(Mono.just(new Person("Robert")), dataBufferFactory, - ResolvableType.forClass(Person.class), JSON).map(DataBuffer::asByteBuffer); - } - - @GetMapping("/raw-flux") - public Flux rawFluxResponseBody() { - return Flux.just(ByteBuffer.wrap("Hello!".getBytes())); - } - - @GetMapping("/raw-observable") - public Observable rawObservableResponseBody() { - return Observable.just(ByteBuffer.wrap("Hello!".getBytes())); - } - - // GET with Person Object(s) response body to "serialize" - - @GetMapping("/person") - public Person personResponseBody() { - return new Person("Robert"); - } - - @GetMapping("/completable-future") - public CompletableFuture completableFutureResponseBody() { - return CompletableFuture.completedFuture(new Person("Robert")); - } - - @GetMapping("/mono") - public Mono monoResponseBody() { - return Mono.just(new Person("Robert")); - } - - @GetMapping("/single") - public Single singleResponseBody() { - return Single.just(new Person("Robert")); - } - - @GetMapping("/monoResponseEntity") - public ResponseEntity> monoResponseEntity() { - Mono body = Mono.just(new Person("Robert")); - return ResponseEntity.ok(body); - } - - @GetMapping("/list") - public List listResponseBody() { - return asList(new Person("Robert"), new Person("Marie")); - } - - @GetMapping("/publisher") - public Publisher publisherResponseBody() { - return Flux.just(new Person("Robert"), new Person("Marie")); - } - - @GetMapping("/flux") - public Flux fluxResponseBody() { - return Flux.just(new Person("Robert"), new Person("Marie")); - } - - @GetMapping("/observable") - public Observable observableResponseBody() { - return Observable.just(new Person("Robert"), new Person("Marie")); - } - - // GET with Resource response body - - @GetMapping("/resource") - public Resource resource() { - return new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class); - } - - // POST with Person "capitalize" name transformation - - @PostMapping("/person-capitalize") - public Person personCapitalize(@RequestBody Person person) { - return new Person(person.getName().toUpperCase()); - } - - @PostMapping("/completable-future-capitalize") - public CompletableFuture completableFutureCapitalize( - @RequestBody CompletableFuture personFuture) { - return personFuture.thenApply(person -> new Person(person.getName().toUpperCase())); - } - - @PostMapping("/mono-capitalize") - public Mono monoCapitalize(@RequestBody Mono personFuture) { - return personFuture.map(person -> new Person(person.getName().toUpperCase())); - } - - @PostMapping("/single-capitalize") - public Single singleCapitalize(@RequestBody Single personFuture) { - return personFuture.map(person -> new Person(person.getName().toUpperCase())); - } - - @PostMapping("/publisher-capitalize") - public Publisher publisherCapitalize(@RequestBody Publisher persons) { - return Flux - .from(persons) - .map(person -> new Person(person.getName().toUpperCase())); - } - - @PostMapping("/flux-capitalize") - public Flux fluxCapitalize(@RequestBody Flux persons) { - return persons.map(person -> new Person(person.getName().toUpperCase())); - } - - @PostMapping("/observable-capitalize") - public Observable observableCapitalize(@RequestBody Observable persons) { - return persons.map(person -> new Person(person.getName().toUpperCase())); - } - - // POST with Objects to "create" - - @PostMapping("/stream-create") - public Publisher streamCreate(@RequestBody Flux personStream) { - return personStream.collectList().doOnSuccess(persons::addAll).then(); - } - - @PostMapping("/publisher-create") - public Publisher publisherCreate(@RequestBody Publisher personStream) { - return Flux.from(personStream).doOnNext(persons::add).then(); - } - - @PostMapping("/flux-create") - public Mono fluxCreate(@RequestBody Flux personStream) { - return personStream.doOnNext(persons::add).then(); - } - - @PostMapping("/observable-create") - public Observable observableCreate(@RequestBody Observable personStream) { - return personStream.toList().doOnNext(persons::addAll).flatMap(document -> Observable.empty()); - } - - // Async stream - @GetMapping("/stream-result") public Publisher stringStreamResponseBody() { return Flux.interval(100).take(5); } - // Error handling - - @GetMapping("/thrown-exception") - public Publisher handleAndThrowException() { - throw new IllegalStateException("Boo"); - } - - @GetMapping("/error-signal") - public Publisher handleWithError() { - return Mono.error(new IllegalStateException("Boo")); - } - - @ExceptionHandler - public Publisher handleException(IllegalStateException ex) { - return Mono.just("Recovered from error: " + ex.getMessage()); - } - - //TODO add mixed and T request mappings tests - - } - - @Controller - @SuppressWarnings("unused") - private static class TestController { - - @GetMapping("/html") - public String getHtmlPage(@RequestParam String name, Model model) { - model.addAttribute("hello", "Hello: " + name + "!"); - return "test"; - } - - } - - @XmlRootElement @SuppressWarnings("WeakerAccess") - private static class Person { - - private String name; - - @SuppressWarnings("unused") - public Person() { - } - - public Person(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - Person person = (Person) o; - return !(this.name != null ? !this.name.equals(person.name) : person.name != null); - } - - @Override - public int hashCode() { - return this.name != null ? this.name.hashCode() : 0; - } - - @Override - public String toString() { - return "Person{" + - "name='" + name + '\'' + - '}'; - } - } - - @XmlRootElement @SuppressWarnings({"WeakerAccess", "unused"}) - private static class People { - - private List persons = new ArrayList<>(); - - public People() { - } - - public People(Person... persons) { - this.persons.addAll(Arrays.asList(persons)); - } - - @XmlElement - public List getPerson() { - return this.persons; - } - } } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java new file mode 100644 index 00000000000..c98fce1eebc --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java @@ -0,0 +1,489 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.reactive.result.method.annotation; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.junit.Test; +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import rx.Observable; +import rx.Single; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.core.ResolvableType; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.http.codec.json.JacksonJsonEncoder; +import org.springframework.http.server.reactive.ZeroCopyIntegrationTests; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.reactive.config.WebReactiveConfiguration; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.springframework.http.MediaType.APPLICATION_XML; + + +/** + * {@code @RequestMapping} integration tests focusing on serialization and + * deserialization of the request and response body. + * + * @author Rossen Stoyanchev + * @author Sebastien Deleuze + */ +public class RequestMappingMessageConversionIntegrationTests extends AbstractRequestMappingIntegrationTests { + + private static final ParameterizedTypeReference> PERSON_LIST = + new ParameterizedTypeReference>() {}; + + private static final MediaType JSON = MediaType.APPLICATION_JSON; + + + @Override + protected ApplicationContext initApplicationContext() { + AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext(); + wac.register(WebConfig.class); + wac.refresh(); + return wac; + } + + + @Test + public void rawPojoResponse() throws Exception { + Person expected = new Person("Robert"); + assertEquals(expected, performGet("/raw", JSON, Person.class).getBody()); + } + + @Test + public void rawFluxResponse() throws Exception { + String expected = "Hello!"; + assertEquals(expected, performGet("/raw-flux", null, String.class).getBody()); + } + + @Test + public void rawObservableResponse() throws Exception { + String expected = "Hello!"; + assertEquals(expected, performGet("/raw-observable", null, String.class).getBody()); + } + + @Test + public void serializeAsPojo() throws Exception { + Person expected = new Person("Robert"); + assertEquals(expected, performGet("/person", JSON, Person.class).getBody()); + } + + @Test + public void serializeAsCompletableFuture() throws Exception { + Person expected = new Person("Robert"); + assertEquals(expected, performGet("/completable-future", JSON, Person.class).getBody()); + } + + @Test + public void serializeAsMono() throws Exception { + Person expected = new Person("Robert"); + assertEquals(expected, performGet("/mono", JSON, Person.class).getBody()); + } + + @Test + public void serializeAsSingle() throws Exception { + Person expected = new Person("Robert"); + assertEquals(expected, performGet("/single", JSON, Person.class).getBody()); + } + + @Test + public void serializeAsMonoResponseEntity() throws Exception { + Person expected = new Person("Robert"); + assertEquals(expected, performGet("/monoResponseEntity", JSON, Person.class).getBody()); + } + + @Test + public void serializeAsList() throws Exception { + List expected = asList(new Person("Robert"), new Person("Marie")); + assertEquals(expected, performGet("/list", JSON, PERSON_LIST).getBody()); + } + + @Test + public void serializeAsPublisher() throws Exception { + List expected = asList(new Person("Robert"), new Person("Marie")); + assertEquals(expected, performGet("/publisher", JSON, PERSON_LIST).getBody()); + } + + @Test + public void serializeAsFlux() throws Exception { + List expected = asList(new Person("Robert"), new Person("Marie")); + assertEquals(expected, performGet("/flux", JSON, PERSON_LIST).getBody()); + } + + @Test + public void serializeAsObservable() throws Exception { + List expected = asList(new Person("Robert"), new Person("Marie")); + assertEquals(expected, performGet("/observable", JSON, PERSON_LIST).getBody()); + } + + @Test + public void resource() throws Exception { + ResponseEntity response = performGet("/resource", null, byte[].class); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertTrue(response.hasBody()); + assertEquals(951, response.getHeaders().getContentLength()); + assertEquals(951, response.getBody().length); + assertEquals(new MediaType("image", "x-png"), response.getHeaders().getContentType()); + } + + @Test + public void personCapitalize() throws Exception { + assertEquals(new Person("ROBERT"), + performPost("/person-capitalize", JSON, new Person("Robert"), + JSON, Person.class).getBody()); + } + + @Test + public void completableFutureCapitalize() throws Exception { + assertEquals(new Person("ROBERT"), + performPost("/completable-future-capitalize", JSON, new Person("Robert"), + JSON, Person.class).getBody()); + } + + @Test + public void monoCapitalize() throws Exception { + assertEquals(new Person("ROBERT"), + performPost("/mono-capitalize", JSON, new Person("Robert"), + JSON, Person.class).getBody()); + } + + @Test + public void singleCapitalize() throws Exception { + assertEquals(new Person("ROBERT"), + performPost("/single-capitalize", JSON, new Person("Robert"), + JSON, Person.class).getBody()); + } + + @Test + public void publisherCapitalize() throws Exception { + List req = asList(new Person("Robert"), new Person("Marie")); + List res = asList(new Person("ROBERT"), new Person("MARIE")); + assertEquals(res, performPost("/publisher-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + } + + @Test + public void fluxCapitalize() throws Exception { + List req = asList(new Person("Robert"), new Person("Marie")); + List res = asList(new Person("ROBERT"), new Person("MARIE")); + assertEquals(res, performPost("/flux-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + } + + @Test + public void observableCapitalize() throws Exception { + List req = asList(new Person("Robert"), new Person("Marie")); + List res = asList(new Person("ROBERT"), new Person("MARIE")); + assertEquals(res, performPost("/observable-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + } + + @Test + public void publisherCreate() throws Exception { + ResponseEntity entity = performPost("/publisher-create", JSON, + asList(new Person("Robert"), new Person("Marie")), null, Void.class); + + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + } + + @Test + public void publisherCreateXml() throws Exception { + People people = new People(new Person("Robert"), new Person("Marie")); + ResponseEntity response = performPost("/publisher-create", APPLICATION_XML, people, null, Void.class); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + } + + @Test + public void fluxCreate() throws Exception { + ResponseEntity entity = performPost("/flux-create", JSON, + asList(new Person("Robert"), new Person("Marie")), null, Void.class); + + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + } + + @Test + public void fluxCreateXml() throws Exception { + People people = new People(new Person("Robert"), new Person("Marie")); + ResponseEntity response = performPost("/flux-create", APPLICATION_XML, people, null, Void.class); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + } + + @Test + public void observableCreate() throws Exception { + ResponseEntity entity = performPost("/observable-create", JSON, + asList(new Person("Robert"), new Person("Marie")), null, Void.class); + + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + } + + @Test + public void observableCreateXml() throws Exception { + People people = new People(new Person("Robert"), new Person("Marie")); + ResponseEntity response = performPost("/observable-create", APPLICATION_XML, people, null, Void.class); + + assertEquals(HttpStatus.OK, response.getStatusCode()); + assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + } + + + @Configuration + @ComponentScan(resourcePattern = "**/RequestMappingMessageConversionIntegrationTests$*.class") + @SuppressWarnings({"unused", "WeakerAccess"}) + static class WebConfig extends WebReactiveConfiguration { + } + + + @RestController + @SuppressWarnings("unused") + private static class TestRestController { + + final List persons = new ArrayList<>(); + + // GET with "raw" data (DataBuffer) response body + + @GetMapping("/raw") + public Publisher rawResponseBody() { + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + JacksonJsonEncoder encoder = new JacksonJsonEncoder(); + return encoder.encode(Mono.just(new Person("Robert")), dataBufferFactory, + ResolvableType.forClass(Person.class), JSON).map(DataBuffer::asByteBuffer); + } + + @GetMapping("/raw-flux") + public Flux rawFluxResponseBody() { + return Flux.just(ByteBuffer.wrap("Hello!".getBytes())); + } + + @GetMapping("/raw-observable") + public Observable rawObservableResponseBody() { + return Observable.just(ByteBuffer.wrap("Hello!".getBytes())); + } + + // GET with Person Object(s) response body to "serialize" + + @GetMapping("/person") + public Person personResponseBody() { + return new Person("Robert"); + } + + @GetMapping("/completable-future") + public CompletableFuture completableFutureResponseBody() { + return CompletableFuture.completedFuture(new Person("Robert")); + } + + @GetMapping("/mono") + public Mono monoResponseBody() { + return Mono.just(new Person("Robert")); + } + + @GetMapping("/single") + public Single singleResponseBody() { + return Single.just(new Person("Robert")); + } + + @GetMapping("/monoResponseEntity") + public ResponseEntity> monoResponseEntity() { + Mono body = Mono.just(new Person("Robert")); + return ResponseEntity.ok(body); + } + + @GetMapping("/list") + public List listResponseBody() { + return asList(new Person("Robert"), new Person("Marie")); + } + + @GetMapping("/publisher") + public Publisher publisherResponseBody() { + return Flux.just(new Person("Robert"), new Person("Marie")); + } + + @GetMapping("/flux") + public Flux fluxResponseBody() { + return Flux.just(new Person("Robert"), new Person("Marie")); + } + + @GetMapping("/observable") + public Observable observableResponseBody() { + return Observable.just(new Person("Robert"), new Person("Marie")); + } + + // GET with Resource response body + + @GetMapping("/resource") + public Resource resource() { + return new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class); + } + + // POST with Person "capitalize" name transformation + + @PostMapping("/person-capitalize") + public Person personCapitalize(@RequestBody Person person) { + return new Person(person.getName().toUpperCase()); + } + + @PostMapping("/completable-future-capitalize") + public CompletableFuture completableFutureCapitalize( + @RequestBody CompletableFuture personFuture) { + return personFuture.thenApply(person -> new Person(person.getName().toUpperCase())); + } + + @PostMapping("/mono-capitalize") + public Mono monoCapitalize(@RequestBody Mono personFuture) { + return personFuture.map(person -> new Person(person.getName().toUpperCase())); + } + + @PostMapping("/single-capitalize") + public Single singleCapitalize(@RequestBody Single personFuture) { + return personFuture.map(person -> new Person(person.getName().toUpperCase())); + } + + @PostMapping("/publisher-capitalize") + public Publisher publisherCapitalize(@RequestBody Publisher persons) { + return Flux + .from(persons) + .map(person -> new Person(person.getName().toUpperCase())); + } + + @PostMapping("/flux-capitalize") + public Flux fluxCapitalize(@RequestBody Flux persons) { + return persons.map(person -> new Person(person.getName().toUpperCase())); + } + + @PostMapping("/observable-capitalize") + public Observable observableCapitalize(@RequestBody Observable persons) { + return persons.map(person -> new Person(person.getName().toUpperCase())); + } + + // POST with Objects to "create" + + @PostMapping("/stream-create") + public Publisher streamCreate(@RequestBody Flux personStream) { + return personStream.collectList().doOnSuccess(persons::addAll).then(); + } + + @PostMapping("/publisher-create") + public Publisher publisherCreate(@RequestBody Publisher personStream) { + return Flux.from(personStream).doOnNext(persons::add).then(); + } + + @PostMapping("/flux-create") + public Mono fluxCreate(@RequestBody Flux personStream) { + return personStream.doOnNext(persons::add).then(); + } + + @PostMapping("/observable-create") + public Observable observableCreate(@RequestBody Observable personStream) { + return personStream.toList().doOnNext(persons::addAll).flatMap(document -> Observable.empty()); + } + } + + @XmlRootElement @SuppressWarnings("WeakerAccess") + private static class Person { + + private String name; + + @SuppressWarnings("unused") + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Person person = (Person) o; + return !(this.name != null ? !this.name.equals(person.name) : person.name != null); + } + + @Override + public int hashCode() { + return this.name != null ? this.name.hashCode() : 0; + } + + @Override + public String toString() { + return "Person{" + + "name='" + name + '\'' + + '}'; + } + } + + @XmlRootElement @SuppressWarnings({"WeakerAccess", "unused"}) + private static class People { + + private List persons = new ArrayList<>(); + + public People() { + } + + public People(Person... persons) { + this.persons.addAll(Arrays.asList(persons)); + } + + @XmlElement + public List getPerson() { + return this.persons; + } + + } + +} diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingViewResolutionIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingViewResolutionIntegrationTests.java new file mode 100644 index 00000000000..9ea276300ac --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingViewResolutionIntegrationTests.java @@ -0,0 +1,93 @@ +/* + * Copyright 2002-2016 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.reactive.result.method.annotation; + +import org.junit.Test; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.reactive.config.ViewResolverRegistry; +import org.springframework.web.reactive.config.WebReactiveConfiguration; +import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer; + +import static org.junit.Assert.assertEquals; + + +/** + * {@code @RequestMapping} integration tests with view resolution scenarios. + * + * @author Rossen Stoyanchev + */ +public class RequestMappingViewResolutionIntegrationTests extends AbstractRequestMappingIntegrationTests { + + + @Override + protected ApplicationContext initApplicationContext() { + AnnotationConfigApplicationContext wac = new AnnotationConfigApplicationContext(); + wac.register(WebConfig.class); + wac.refresh(); + return wac; + } + + + @Test + public void html() throws Exception { + String expected = "Hello: Jason!"; + assertEquals(expected, performGet("/html?name=Jason", MediaType.TEXT_HTML, String.class).getBody()); + } + + + @Configuration + @ComponentScan(resourcePattern = "**/RequestMappingViewResolutionIntegrationTests$*.class") + @SuppressWarnings({"unused", "WeakerAccess"}) + static class WebConfig extends WebReactiveConfiguration { + + @Override + protected void configureViewResolvers(ViewResolverRegistry registry) { + registry.freeMarker(); + } + + @Bean + public FreeMarkerConfigurer freeMarkerConfig() { + FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); + configurer.setPreferFileSystemAccess(false); + configurer.setTemplateLoaderPath("classpath*:org/springframework/web/reactive/view/freemarker/"); + return configurer; + } + + } + + @Controller + @SuppressWarnings("unused") + private static class TestController { + + @GetMapping("/html") + public String getHtmlPage(@RequestParam String name, Model model) { + model.addAttribute("hello", "Hello: " + name + "!"); + return "test"; + } + } + +} From aa47616be231133236e87cef7af1a569677a7792 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 11 Jul 2016 18:02:34 -0400 Subject: [PATCH 5/5] Split TestRestController into use-case sub-classes --- ...pingMessageConversionIntegrationTests.java | 220 +++++++++--------- 1 file changed, 115 insertions(+), 105 deletions(-) diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java index c98fce1eebc..7991dd14e68 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingMessageConversionIntegrationTests.java @@ -50,6 +50,7 @@ import org.springframework.http.server.reactive.ZeroCopyIntegrationTests; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.reactive.config.WebReactiveConfiguration; @@ -84,75 +85,75 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq @Test - public void rawPojoResponse() throws Exception { + public void byteBufferResponseBodyWithPublisher() throws Exception { Person expected = new Person("Robert"); - assertEquals(expected, performGet("/raw", JSON, Person.class).getBody()); + assertEquals(expected, performGet("/raw-response/publisher", JSON, Person.class).getBody()); } @Test - public void rawFluxResponse() throws Exception { + public void byteBufferResponseBodyWithFlux() throws Exception { String expected = "Hello!"; - assertEquals(expected, performGet("/raw-flux", null, String.class).getBody()); + assertEquals(expected, performGet("/raw-response/flux", null, String.class).getBody()); } @Test - public void rawObservableResponse() throws Exception { + public void byteBufferResponseBodyWithObservable() throws Exception { String expected = "Hello!"; - assertEquals(expected, performGet("/raw-observable", null, String.class).getBody()); + assertEquals(expected, performGet("/raw-response/observable", null, String.class).getBody()); } @Test - public void serializeAsPojo() throws Exception { + public void personResponseBody() throws Exception { Person expected = new Person("Robert"); - assertEquals(expected, performGet("/person", JSON, Person.class).getBody()); + assertEquals(expected, performGet("/person-response/person", JSON, Person.class).getBody()); } @Test - public void serializeAsCompletableFuture() throws Exception { + public void personResponseBodyWithCompletableFuture() throws Exception { Person expected = new Person("Robert"); - assertEquals(expected, performGet("/completable-future", JSON, Person.class).getBody()); + assertEquals(expected, performGet("/person-response/completable-future", JSON, Person.class).getBody()); } @Test - public void serializeAsMono() throws Exception { + public void personResponseBodyWithMono() throws Exception { Person expected = new Person("Robert"); - assertEquals(expected, performGet("/mono", JSON, Person.class).getBody()); + assertEquals(expected, performGet("/person-response/mono", JSON, Person.class).getBody()); } @Test - public void serializeAsSingle() throws Exception { + public void personResponseBodyWithSingle() throws Exception { Person expected = new Person("Robert"); - assertEquals(expected, performGet("/single", JSON, Person.class).getBody()); + assertEquals(expected, performGet("/person-response/single", JSON, Person.class).getBody()); } @Test - public void serializeAsMonoResponseEntity() throws Exception { + public void personResponseBodyWithMonoResponseEntity() throws Exception { Person expected = new Person("Robert"); - assertEquals(expected, performGet("/monoResponseEntity", JSON, Person.class).getBody()); + assertEquals(expected, performGet("/person-response/mono-response-entity", JSON, Person.class).getBody()); } @Test - public void serializeAsList() throws Exception { + public void personResponseBodyWithList() throws Exception { List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/list", JSON, PERSON_LIST).getBody()); + assertEquals(expected, performGet("/person-response/list", JSON, PERSON_LIST).getBody()); } @Test - public void serializeAsPublisher() throws Exception { + public void personResponseBodyWithPublisher() throws Exception { List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/publisher", JSON, PERSON_LIST).getBody()); + assertEquals(expected, performGet("/person-response/publisher", JSON, PERSON_LIST).getBody()); } @Test - public void serializeAsFlux() throws Exception { + public void personResponseBodyWithFlux() throws Exception { List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/flux", JSON, PERSON_LIST).getBody()); + assertEquals(expected, performGet("/person-response/flux", JSON, PERSON_LIST).getBody()); } @Test - public void serializeAsObservable() throws Exception { + public void personResponseBodyWithObservable() throws Exception { List expected = asList(new Person("Robert"), new Person("Marie")); - assertEquals(expected, performGet("/observable", JSON, PERSON_LIST).getBody()); + assertEquals(expected, performGet("/person-response/observable", JSON, PERSON_LIST).getBody()); } @Test @@ -167,106 +168,106 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq } @Test - public void personCapitalize() throws Exception { + public void personTransform() throws Exception { assertEquals(new Person("ROBERT"), - performPost("/person-capitalize", JSON, new Person("Robert"), + performPost("/person-transform/person", JSON, new Person("Robert"), JSON, Person.class).getBody()); } @Test - public void completableFutureCapitalize() throws Exception { + public void personTransformWithCompletableFuture() throws Exception { assertEquals(new Person("ROBERT"), - performPost("/completable-future-capitalize", JSON, new Person("Robert"), + performPost("/person-transform/completable-future", JSON, new Person("Robert"), JSON, Person.class).getBody()); } @Test - public void monoCapitalize() throws Exception { + public void personTransformWithMono() throws Exception { assertEquals(new Person("ROBERT"), - performPost("/mono-capitalize", JSON, new Person("Robert"), + performPost("/person-transform/mono", JSON, new Person("Robert"), JSON, Person.class).getBody()); } @Test - public void singleCapitalize() throws Exception { + public void personTransformWithSingle() throws Exception { assertEquals(new Person("ROBERT"), - performPost("/single-capitalize", JSON, new Person("Robert"), + performPost("/person-transform/single", JSON, new Person("Robert"), JSON, Person.class).getBody()); } @Test - public void publisherCapitalize() throws Exception { + public void personTransformWithPublisher() throws Exception { List req = asList(new Person("Robert"), new Person("Marie")); List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/publisher-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + assertEquals(res, performPost("/person-transform/publisher", JSON, req, JSON, PERSON_LIST).getBody()); } @Test - public void fluxCapitalize() throws Exception { + public void personTransformWithFlux() throws Exception { List req = asList(new Person("Robert"), new Person("Marie")); List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/flux-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + assertEquals(res, performPost("/person-transform/flux", JSON, req, JSON, PERSON_LIST).getBody()); } @Test - public void observableCapitalize() throws Exception { + public void personTransformWithObservable() throws Exception { List req = asList(new Person("Robert"), new Person("Marie")); List res = asList(new Person("ROBERT"), new Person("MARIE")); - assertEquals(res, performPost("/observable-capitalize", JSON, req, JSON, PERSON_LIST).getBody()); + assertEquals(res, performPost("/person-transform/observable", JSON, req, JSON, PERSON_LIST).getBody()); } @Test - public void publisherCreate() throws Exception { - ResponseEntity entity = performPost("/publisher-create", JSON, + public void personCreateWithPublisherJson() throws Exception { + ResponseEntity entity = performPost("/person-create/publisher", JSON, asList(new Person("Robert"), new Person("Marie")), null, Void.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(PersonCreateController.class).persons.size()); } @Test - public void publisherCreateXml() throws Exception { + public void personCreateWithPublisherXml() throws Exception { People people = new People(new Person("Robert"), new Person("Marie")); - ResponseEntity response = performPost("/publisher-create", APPLICATION_XML, people, null, Void.class); + ResponseEntity response = performPost("/person-create/publisher", APPLICATION_XML, people, null, Void.class); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(PersonCreateController.class).persons.size()); } @Test - public void fluxCreate() throws Exception { - ResponseEntity entity = performPost("/flux-create", JSON, + public void personCreateWithFluxJson() throws Exception { + ResponseEntity entity = performPost("/person-create/flux", JSON, asList(new Person("Robert"), new Person("Marie")), null, Void.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(PersonCreateController.class).persons.size()); } @Test - public void fluxCreateXml() throws Exception { + public void personCreateWithFluxXml() throws Exception { People people = new People(new Person("Robert"), new Person("Marie")); - ResponseEntity response = performPost("/flux-create", APPLICATION_XML, people, null, Void.class); + ResponseEntity response = performPost("/person-create/flux", APPLICATION_XML, people, null, Void.class); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(PersonCreateController.class).persons.size()); } @Test - public void observableCreate() throws Exception { - ResponseEntity entity = performPost("/observable-create", JSON, + public void personCreateWithObservableJson() throws Exception { + ResponseEntity entity = performPost("/person-create/observable", JSON, asList(new Person("Robert"), new Person("Marie")), null, Void.class); assertEquals(HttpStatus.OK, entity.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(PersonCreateController.class).persons.size()); } @Test - public void observableCreateXml() throws Exception { + public void personCreateWithObservableXml() throws Exception { People people = new People(new Person("Robert"), new Person("Marie")); - ResponseEntity response = performPost("/observable-create", APPLICATION_XML, people, null, Void.class); + ResponseEntity response = performPost("/person-create/observable", APPLICATION_XML, people, null, Void.class); assertEquals(HttpStatus.OK, response.getStatusCode()); - assertEquals(2, getApplicationContext().getBean(TestRestController.class).persons.size()); + assertEquals(2, getApplicationContext().getBean(PersonCreateController.class).persons.size()); } @@ -278,145 +279,154 @@ public class RequestMappingMessageConversionIntegrationTests extends AbstractReq @RestController + @RequestMapping("/raw-response") @SuppressWarnings("unused") - private static class TestRestController { + private static class RawResponseBodyController { - final List persons = new ArrayList<>(); - - // GET with "raw" data (DataBuffer) response body - - @GetMapping("/raw") - public Publisher rawResponseBody() { + @GetMapping("/publisher") + public Publisher getPublisher() { DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); JacksonJsonEncoder encoder = new JacksonJsonEncoder(); return encoder.encode(Mono.just(new Person("Robert")), dataBufferFactory, ResolvableType.forClass(Person.class), JSON).map(DataBuffer::asByteBuffer); } - @GetMapping("/raw-flux") - public Flux rawFluxResponseBody() { + @GetMapping("/flux") + public Flux getFlux() { return Flux.just(ByteBuffer.wrap("Hello!".getBytes())); } - @GetMapping("/raw-observable") - public Observable rawObservableResponseBody() { + @GetMapping("/observable") + public Observable getObservable() { return Observable.just(ByteBuffer.wrap("Hello!".getBytes())); } + } - // GET with Person Object(s) response body to "serialize" + @RestController + @RequestMapping("/person-response") + @SuppressWarnings("unused") + private static class PersonResponseBodyController { @GetMapping("/person") - public Person personResponseBody() { + public Person getPerson() { return new Person("Robert"); } @GetMapping("/completable-future") - public CompletableFuture completableFutureResponseBody() { + public CompletableFuture getCompletableFuture() { return CompletableFuture.completedFuture(new Person("Robert")); } @GetMapping("/mono") - public Mono monoResponseBody() { + public Mono getMono() { return Mono.just(new Person("Robert")); } @GetMapping("/single") - public Single singleResponseBody() { + public Single getSingle() { return Single.just(new Person("Robert")); } - @GetMapping("/monoResponseEntity") - public ResponseEntity> monoResponseEntity() { + @GetMapping("/mono-response-entity") + public ResponseEntity> getMonoResponseEntity() { Mono body = Mono.just(new Person("Robert")); return ResponseEntity.ok(body); } @GetMapping("/list") - public List listResponseBody() { + public List getList() { return asList(new Person("Robert"), new Person("Marie")); } @GetMapping("/publisher") - public Publisher publisherResponseBody() { + public Publisher getPublisher() { return Flux.just(new Person("Robert"), new Person("Marie")); } @GetMapping("/flux") - public Flux fluxResponseBody() { + public Flux getFlux() { return Flux.just(new Person("Robert"), new Person("Marie")); } @GetMapping("/observable") - public Observable observableResponseBody() { + public Observable getObservable() { return Observable.just(new Person("Robert"), new Person("Marie")); } + } - // GET with Resource response body + @RestController + @SuppressWarnings("unused") + private static class ResourceController { @GetMapping("/resource") public Resource resource() { return new ClassPathResource("spring.png", ZeroCopyIntegrationTests.class); } + } - // POST with Person "capitalize" name transformation + @RestController + @RequestMapping("/person-transform") + @SuppressWarnings("unused") + private static class PersonTransformationController { - @PostMapping("/person-capitalize") - public Person personCapitalize(@RequestBody Person person) { + @PostMapping("/person") + public Person transformPerson(@RequestBody Person person) { return new Person(person.getName().toUpperCase()); } - @PostMapping("/completable-future-capitalize") - public CompletableFuture completableFutureCapitalize( + @PostMapping("/completable-future") + public CompletableFuture transformCompletableFuture( @RequestBody CompletableFuture personFuture) { return personFuture.thenApply(person -> new Person(person.getName().toUpperCase())); } - @PostMapping("/mono-capitalize") - public Mono monoCapitalize(@RequestBody Mono personFuture) { + @PostMapping("/mono") + public Mono transformMono(@RequestBody Mono personFuture) { return personFuture.map(person -> new Person(person.getName().toUpperCase())); } - @PostMapping("/single-capitalize") - public Single singleCapitalize(@RequestBody Single personFuture) { + @PostMapping("/single") + public Single transformSingle(@RequestBody Single personFuture) { return personFuture.map(person -> new Person(person.getName().toUpperCase())); } - @PostMapping("/publisher-capitalize") - public Publisher publisherCapitalize(@RequestBody Publisher persons) { + @PostMapping("/publisher") + public Publisher transformPublisher(@RequestBody Publisher persons) { return Flux .from(persons) .map(person -> new Person(person.getName().toUpperCase())); } - @PostMapping("/flux-capitalize") - public Flux fluxCapitalize(@RequestBody Flux persons) { + @PostMapping("/flux") + public Flux transformFlux(@RequestBody Flux persons) { return persons.map(person -> new Person(person.getName().toUpperCase())); } - @PostMapping("/observable-capitalize") - public Observable observableCapitalize(@RequestBody Observable persons) { + @PostMapping("/observable") + public Observable transformObservable(@RequestBody Observable persons) { return persons.map(person -> new Person(person.getName().toUpperCase())); } + } - // POST with Objects to "create" + @RestController + @RequestMapping("/person-create") + @SuppressWarnings("unused") + private static class PersonCreateController { - @PostMapping("/stream-create") - public Publisher streamCreate(@RequestBody Flux personStream) { - return personStream.collectList().doOnSuccess(persons::addAll).then(); - } + final List persons = new ArrayList<>(); - @PostMapping("/publisher-create") - public Publisher publisherCreate(@RequestBody Publisher personStream) { + @PostMapping("/publisher") + public Publisher createWithPublisher(@RequestBody Publisher personStream) { return Flux.from(personStream).doOnNext(persons::add).then(); } - @PostMapping("/flux-create") - public Mono fluxCreate(@RequestBody Flux personStream) { + @PostMapping("/flux") + public Mono createWithFlux(@RequestBody Flux personStream) { return personStream.doOnNext(persons::add).then(); } - @PostMapping("/observable-create") - public Observable observableCreate(@RequestBody Observable personStream) { + @PostMapping("/observable") + public Observable createWithObservable(@RequestBody Observable personStream) { return personStream.toList().doOnNext(persons::addAll).flatMap(document -> Observable.empty()); } }