Refactor @ResponseBody and ResponseEntity tests
Introduce separate test classes for each base class in the hierarchy above @ResponseBody and ResponseEntity result handlers. Also start porting existing unit test cases for @ResponseBody and ResponseEntity return value handlers.
This commit is contained in:
parent
3fe87ee225
commit
cae8800183
|
@ -126,7 +126,7 @@ public abstract class ContentNegotiatingResultHandlerSupport implements Ordered
|
|||
}
|
||||
|
||||
private List<MediaType> getAcceptableTypes(ServerWebExchange exchange) {
|
||||
List<MediaType> mediaTypes = this.contentTypeResolver.resolveMediaTypes(exchange);
|
||||
List<MediaType> mediaTypes = getContentTypeResolver().resolveMediaTypes(exchange);
|
||||
return (mediaTypes.isEmpty() ? Collections.singletonList(MediaType.ALL) : mediaTypes);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
|
@ -82,16 +83,22 @@ public abstract class AbstractMessageConverterResultHandler extends ContentNegot
|
|||
publisher = Mono.empty();
|
||||
}
|
||||
elementType = bodyType.getGeneric(0);
|
||||
if (Void.class.equals(elementType.getRawClass())) {
|
||||
return Mono.from((Publisher<Void>) publisher);
|
||||
}
|
||||
}
|
||||
else {
|
||||
publisher = Mono.justOrEmpty(body);
|
||||
elementType = bodyType;
|
||||
}
|
||||
|
||||
if (Void.class.equals(elementType.getRawClass())) {
|
||||
return Mono.from((Publisher<Void>) publisher);
|
||||
}
|
||||
|
||||
List<MediaType> producibleTypes = getProducibleMediaTypes(elementType);
|
||||
if (producibleTypes.isEmpty()) {
|
||||
return Mono.error(new IllegalStateException(
|
||||
"No converter for return value type: " + elementType));
|
||||
}
|
||||
|
||||
MediaType bestMediaType = selectMediaType(exchange, producibleTypes);
|
||||
|
||||
if (bestMediaType != null) {
|
||||
|
|
|
@ -104,7 +104,7 @@ public class ResponseEntityResultHandler extends AbstractMessageConverterResultH
|
|||
|
||||
if (!entityHeaders.isEmpty()) {
|
||||
entityHeaders.entrySet().stream()
|
||||
.filter(entry -> responseHeaders.containsKey(entry.getKey()))
|
||||
.filter(entry -> !responseHeaders.containsKey(entry.getKey()))
|
||||
.forEach(entry -> responseHeaders.put(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.web.reactive.accept.FixedContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.server.session.WebSessionManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.http.MediaType.ALL;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;
|
||||
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM;
|
||||
import static org.springframework.http.MediaType.IMAGE_GIF;
|
||||
import static org.springframework.http.MediaType.IMAGE_JPEG;
|
||||
import static org.springframework.http.MediaType.IMAGE_PNG;
|
||||
import static org.springframework.http.MediaType.TEXT_PLAIN;
|
||||
import static org.springframework.web.reactive.HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ContentNegotiatingResultHandlerSupport}.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ContentNegotiatingResultHandlerSupportTests {
|
||||
|
||||
private TestHandlerSupport handlerSupport;
|
||||
|
||||
private MockServerHttpRequest request;
|
||||
|
||||
private ServerWebExchange exchange;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.handlerSupport = new TestHandlerSupport();
|
||||
this.request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path"));
|
||||
this.exchange = new DefaultServerWebExchange(
|
||||
this.request, new MockServerHttpResponse(), mock(WebSessionManager.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void usesContentTypeResolver() throws Exception {
|
||||
RequestedContentTypeResolver resolver = new FixedContentTypeResolver(IMAGE_GIF);
|
||||
TestHandlerSupport handlerSupport = new TestHandlerSupport(resolver);
|
||||
|
||||
List<MediaType> mediaTypes = Arrays.asList(IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG);
|
||||
MediaType actual = handlerSupport.selectMediaType(this.exchange, mediaTypes);
|
||||
|
||||
assertEquals(IMAGE_GIF, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void producibleMediaTypesRequestAttribute() throws Exception {
|
||||
Set<MediaType> producible = Collections.singleton(IMAGE_GIF);
|
||||
this.exchange.getAttributes().put(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, producible);
|
||||
|
||||
List<MediaType> mediaTypes = Arrays.asList(IMAGE_JPEG, IMAGE_GIF, IMAGE_PNG);
|
||||
MediaType actual = handlerSupport.selectMediaType(this.exchange, mediaTypes);
|
||||
|
||||
assertEquals(IMAGE_GIF, actual);
|
||||
}
|
||||
|
||||
@Test // SPR-9160
|
||||
public void sortsByQuality() throws Exception {
|
||||
this.request.getHeaders().add("Accept", "text/plain; q=0.5, application/json");
|
||||
|
||||
List<MediaType> mediaTypes = Arrays.asList(TEXT_PLAIN, APPLICATION_JSON_UTF8);
|
||||
MediaType actual = this.handlerSupport.selectMediaType(this.exchange, mediaTypes);
|
||||
|
||||
assertEquals(APPLICATION_JSON_UTF8, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void charsetFromAcceptHeader() throws Exception {
|
||||
MediaType text8859 = MediaType.parseMediaType("text/plain;charset=ISO-8859-1");
|
||||
MediaType textUtf8 = MediaType.parseMediaType("text/plain;charset=UTF-8");
|
||||
|
||||
this.request.getHeaders().setAccept(Collections.singletonList(text8859));
|
||||
MediaType actual = this.handlerSupport.selectMediaType(this.exchange, Collections.singletonList(textUtf8));
|
||||
|
||||
assertEquals(text8859, actual);
|
||||
}
|
||||
|
||||
@Test // SPR-12894
|
||||
public void noConcreteMediaType() throws Exception {
|
||||
List<MediaType> producible = Collections.singletonList(ALL);
|
||||
MediaType actual = this.handlerSupport.selectMediaType(this.exchange, producible);
|
||||
|
||||
assertEquals(APPLICATION_OCTET_STREAM, actual);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private static class TestHandlerSupport extends ContentNegotiatingResultHandlerSupport {
|
||||
|
||||
protected TestHandlerSupport() {
|
||||
this(new HeaderContentTypeResolver());
|
||||
}
|
||||
|
||||
public TestHandlerSupport(RequestedContentTypeResolver contentTypeResolver) {
|
||||
super(new GenericConversionService(), contentTypeResolver);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* 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.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URI;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.test.TestSubscriber;
|
||||
import rx.Observable;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.Decoder;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.support.ByteBufferDecoder;
|
||||
import org.springframework.core.codec.support.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.support.JacksonJsonDecoder;
|
||||
import org.springframework.core.codec.support.JacksonJsonEncoder;
|
||||
import org.springframework.core.codec.support.Jaxb2Decoder;
|
||||
import org.springframework.core.codec.support.Jaxb2Encoder;
|
||||
import org.springframework.core.codec.support.JsonObjectDecoder;
|
||||
import org.springframework.core.codec.support.StringDecoder;
|
||||
import org.springframework.core.codec.support.StringEncoder;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.converter.reactive.CodecHttpMessageConverter;
|
||||
import org.springframework.http.converter.reactive.HttpMessageConverter;
|
||||
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter;
|
||||
import org.springframework.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.server.session.WebSessionManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AbstractMessageConverterResultHandler}.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class MessageConverterResultHandlerTests {
|
||||
|
||||
private AbstractMessageConverterResultHandler resultHandler;
|
||||
|
||||
private MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
|
||||
private ServerWebExchange exchange;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.resultHandler = createResultHandler();
|
||||
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path"));
|
||||
this.exchange = new DefaultServerWebExchange(request, this.response, mock(WebSessionManager.class));
|
||||
}
|
||||
|
||||
|
||||
@Test // SPR-12894
|
||||
@Ignore // GH # 121
|
||||
public void useDefaultContentType() throws Exception {
|
||||
Object body = new ByteArrayResource("body".getBytes("UTF-8"));
|
||||
ResolvableType bodyType = ResolvableType.forType(Resource.class);
|
||||
this.resultHandler.writeBody(this.exchange, body, bodyType).block(Duration.ofSeconds(5));
|
||||
|
||||
assertEquals("image/jpeg", this.response.getHeaders().getFirst("Content-Type"));
|
||||
TestSubscriber.subscribe(this.response.getBody())
|
||||
.assertValuesWith(buf -> assertEquals("body",
|
||||
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void voidReturnType() throws Exception {
|
||||
testVoidReturnType(null, ResolvableType.forType(Void.class));
|
||||
testVoidReturnType(Mono.empty(), ResolvableType.forClassWithGenerics(Mono.class, Void.class));
|
||||
testVoidReturnType(Flux.empty(), ResolvableType.forClassWithGenerics(Flux.class, Void.class));
|
||||
testVoidReturnType(Observable.empty(), ResolvableType.forClassWithGenerics(Observable.class, Void.class));
|
||||
}
|
||||
|
||||
private void testVoidReturnType(Object body, ResolvableType bodyType) {
|
||||
this.resultHandler.writeBody(this.exchange, body, bodyType).block(Duration.ofSeconds(5));
|
||||
|
||||
assertNull(this.response.getHeaders().get("Content-Type"));
|
||||
assertNull(this.response.getBody());
|
||||
}
|
||||
|
||||
@Test // SPR-13135
|
||||
public void unsupportedReturnType() throws Exception {
|
||||
ByteArrayOutputStream body = new ByteArrayOutputStream();
|
||||
ResolvableType bodyType = ResolvableType.forType(OutputStream.class);
|
||||
|
||||
HttpMessageConverter<?> converter = new CodecHttpMessageConverter<>(new ByteBufferEncoder());
|
||||
Mono<Void> mono = createResultHandler(converter).writeBody(this.exchange, body, bodyType);
|
||||
|
||||
TestSubscriber.subscribe(mono).assertError(IllegalStateException.class);
|
||||
}
|
||||
|
||||
|
||||
private AbstractMessageConverterResultHandler createResultHandler(HttpMessageConverter<?>... converters) {
|
||||
List<HttpMessageConverter<?>> converterList;
|
||||
if (ObjectUtils.isEmpty(converters)) {
|
||||
converterList = new ArrayList<>();
|
||||
converterList.add(new CodecHttpMessageConverter<>(new ByteBufferEncoder()));
|
||||
converterList.add(new CodecHttpMessageConverter<>(new StringEncoder()));
|
||||
converterList.add(new ResourceHttpMessageConverter());
|
||||
converterList.add(new CodecHttpMessageConverter<>(new Jaxb2Encoder()));
|
||||
converterList.add(new CodecHttpMessageConverter<>(new JacksonJsonEncoder()));
|
||||
}
|
||||
else {
|
||||
converterList = Arrays.asList(converters);
|
||||
}
|
||||
|
||||
GenericConversionService service = new GenericConversionService();
|
||||
service.addConverter(new ReactiveStreamsToCompletableFutureConverter());
|
||||
service.addConverter(new ReactiveStreamsToRxJava1Converter());
|
||||
|
||||
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
|
||||
|
||||
return new AbstractMessageConverterResultHandler(converterList, service, resolver) {};
|
||||
}
|
||||
|
||||
}
|
|
@ -17,143 +17,154 @@
|
|||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.support.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.support.JacksonJsonEncoder;
|
||||
import org.springframework.core.codec.support.Jaxb2Encoder;
|
||||
import org.springframework.core.codec.support.StringEncoder;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.reactive.CodecHttpMessageConverter;
|
||||
import org.springframework.http.converter.reactive.HttpMessageConverter;
|
||||
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter;
|
||||
import org.springframework.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.reactive.HandlerMapping;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.HandlerResultHandler;
|
||||
import org.springframework.web.reactive.accept.FixedContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.server.session.WebSessionManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;
|
||||
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ResponseBodyResultHandler}.
|
||||
*
|
||||
* consider whether the logic under test is in a parent class, then see:
|
||||
* <ul>
|
||||
* <li>{@code MessageConverterResultHandlerTests},
|
||||
* <li>{@code ContentNegotiatingResultHandlerSupportTests}
|
||||
* </ul>
|
||||
* @author Sebastien Deleuze
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ResponseBodyResultHandlerTests {
|
||||
|
||||
private ResponseBodyResultHandler resultHandler;
|
||||
|
||||
private MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
|
||||
private ServerWebExchange exchange;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.resultHandler = createHandler();
|
||||
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path"));
|
||||
this.exchange = new DefaultServerWebExchange(request, this.response, mock(WebSessionManager.class));
|
||||
}
|
||||
|
||||
|
||||
private ResponseBodyResultHandler createHandler(HttpMessageConverter<?>... converters) {
|
||||
List<HttpMessageConverter<?>> converterList;
|
||||
if (ObjectUtils.isEmpty(converters)) {
|
||||
converterList = new ArrayList<>();
|
||||
converterList.add(new CodecHttpMessageConverter<>(new ByteBufferEncoder()));
|
||||
converterList.add(new CodecHttpMessageConverter<>(new StringEncoder()));
|
||||
converterList.add(new ResourceHttpMessageConverter());
|
||||
converterList.add(new CodecHttpMessageConverter<>(new Jaxb2Encoder()));
|
||||
converterList.add(new CodecHttpMessageConverter<>(new JacksonJsonEncoder()));
|
||||
}
|
||||
else {
|
||||
converterList = Arrays.asList(converters);
|
||||
}
|
||||
GenericConversionService service = new GenericConversionService();
|
||||
service.addConverter(new ReactiveStreamsToCompletableFutureConverter());
|
||||
service.addConverter(new ReactiveStreamsToRxJava1Converter());
|
||||
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
|
||||
|
||||
return new ResponseBodyResultHandler(converterList, new DefaultConversionService(), resolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supports() throws NoSuchMethodException {
|
||||
ResponseBodyResultHandler handler = createHandler(new StringEncoder());
|
||||
TestController controller = new TestController();
|
||||
testSupports(controller, "handleReturningString", true);
|
||||
testSupports(controller, "handleReturningVoid", true);
|
||||
testSupports(controller, "doWork", false);
|
||||
|
||||
HandlerMethod hm = new HandlerMethod(controller, TestController.class.getMethod("notAnnotated"));
|
||||
TestRestController restController = new TestRestController();
|
||||
testSupports(restController, "handleReturningString", true);
|
||||
testSupports(restController, "handleReturningVoid", true);
|
||||
}
|
||||
|
||||
private void testSupports(Object controller, String method, boolean result) throws NoSuchMethodException {
|
||||
HandlerMethod hm = handlerMethod(controller, method);
|
||||
ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType());
|
||||
assertFalse(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
|
||||
|
||||
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherString"));
|
||||
type = ResolvableType.forMethodParameter(hm.getReturnType());
|
||||
assertTrue(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
|
||||
|
||||
hm = new HandlerMethod(controller, TestController.class.getMethod("publisherVoid"));
|
||||
type = ResolvableType.forMethodParameter(hm.getReturnType());
|
||||
assertTrue(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
|
||||
HandlerResult handlerResult = new HandlerResult(hm, null, type, new ExtendedModelMap());
|
||||
assertEquals(result, this.resultHandler.supports(handlerResult));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultOrder() throws Exception {
|
||||
ResponseBodyResultHandler handler = createHandler(new StringEncoder());
|
||||
assertEquals(100, handler.getOrder());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesContentTypeResolver() throws Exception {
|
||||
RequestedContentTypeResolver resolver = new FixedContentTypeResolver(APPLICATION_JSON_UTF8);
|
||||
HandlerResultHandler handler = createHandler(resolver, new StringEncoder(), new JacksonJsonEncoder());
|
||||
|
||||
ServerWebExchange exchange = createExchange("/foo");
|
||||
HandlerResult result = new HandlerResult(new Object(), "fooValue", ResolvableType.forClass(String.class));
|
||||
handler.handleResult(exchange, result).block();
|
||||
|
||||
assertEquals(APPLICATION_JSON_UTF8, exchange.getResponse().getHeaders().getContentType());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsProducibleMediaTypesAttribute() throws Exception {
|
||||
ServerWebExchange exchange = createExchange("/foo");
|
||||
Set<MediaType> mediaTypes = Collections.singleton(MediaType.APPLICATION_JSON);
|
||||
exchange.getAttributes().put(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
|
||||
|
||||
HandlerResultHandler handler = createHandler(new StringEncoder(), new JacksonJsonEncoder());
|
||||
|
||||
HandlerResult result = new HandlerResult(new Object(), "fooValue", ResolvableType.forClass(String.class));
|
||||
handler.handleResult(exchange, result).block();
|
||||
|
||||
assertEquals(MediaType.APPLICATION_JSON, exchange.getResponse().getHeaders().getContentType());
|
||||
assertEquals(100, this.resultHandler.getOrder());
|
||||
}
|
||||
|
||||
|
||||
private ResponseBodyResultHandler createHandler(Encoder<?>... encoders) {
|
||||
return createHandler(new HeaderContentTypeResolver(), encoders);
|
||||
}
|
||||
|
||||
private ResponseBodyResultHandler createHandler(RequestedContentTypeResolver resolver,
|
||||
Encoder<?>... encoders) {
|
||||
|
||||
List<HttpMessageConverter<?>> converters = Arrays.stream(encoders)
|
||||
.map(encoder -> new CodecHttpMessageConverter<>(encoder, null))
|
||||
.collect(Collectors.toList());
|
||||
return new ResponseBodyResultHandler(converters, new DefaultConversionService(), resolver);
|
||||
}
|
||||
|
||||
private ServerWebExchange createExchange(String path) throws URISyntaxException {
|
||||
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI(path));
|
||||
WebSessionManager sessionManager = mock(WebSessionManager.class);
|
||||
return new DefaultServerWebExchange(request, new MockServerHttpResponse(), sessionManager);
|
||||
private HandlerMethod handlerMethod(Object controller, String method) throws NoSuchMethodException {
|
||||
return new HandlerMethod(controller, controller.getClass().getMethod(method));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@RestController @SuppressWarnings("unused")
|
||||
private static class TestRestController {
|
||||
|
||||
public String handleReturningString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Void handleReturningVoid() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Controller @SuppressWarnings("unused")
|
||||
private static class TestController {
|
||||
|
||||
public Publisher<String> notAnnotated() {
|
||||
@ResponseBody
|
||||
public String handleReturningString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
public Publisher<String> publisherString() {
|
||||
public Void handleReturningVoid() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ResponseBody
|
||||
public Publisher<Void> publisherVoid() {
|
||||
public String doWork() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,134 +16,139 @@
|
|||
package org.springframework.web.reactive.result.method.annotation;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.test.TestSubscriber;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.support.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.support.JacksonJsonEncoder;
|
||||
import org.springframework.core.codec.support.Jaxb2Encoder;
|
||||
import org.springframework.core.codec.support.StringEncoder;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.io.buffer.support.DataBufferTestUtils;
|
||||
import org.springframework.core.convert.support.GenericConversionService;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToCompletableFutureConverter;
|
||||
import org.springframework.core.convert.support.ReactiveStreamsToRxJava1Converter;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.converter.reactive.CodecHttpMessageConverter;
|
||||
import org.springframework.http.converter.reactive.HttpMessageConverter;
|
||||
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter;
|
||||
import org.springframework.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.HandlerResultHandler;
|
||||
import org.springframework.web.reactive.accept.FixedContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.HeaderContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||
import org.springframework.web.server.session.WebSessionManager;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.springframework.http.MediaType.APPLICATION_JSON_UTF8;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ResponseEntityResultHandler}.
|
||||
* Unit tests for {@link ResponseEntityResultHandler}. When adding a test also
|
||||
* consider whether the logic under test is in a parent class, then see:
|
||||
* <ul>
|
||||
* <li>{@code MessageConverterResultHandlerTests},
|
||||
* <li>{@code ContentNegotiatingResultHandlerSupportTests}
|
||||
* </ul>
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ResponseEntityResultHandlerTests {
|
||||
|
||||
private static final Object HANDLER = new Object();
|
||||
|
||||
|
||||
private ResponseEntityResultHandler resultHandler;
|
||||
|
||||
private MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
|
||||
private ServerWebExchange exchange;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
this.resultHandler = createHandler();
|
||||
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI("/path"));
|
||||
this.exchange = new DefaultServerWebExchange(request, this.response, mock(WebSessionManager.class));
|
||||
}
|
||||
|
||||
private ResponseEntityResultHandler createHandler(HttpMessageConverter<?>... converters) {
|
||||
List<HttpMessageConverter<?>> converterList;
|
||||
if (ObjectUtils.isEmpty(converters)) {
|
||||
converterList = new ArrayList<>();
|
||||
converterList.add(new CodecHttpMessageConverter<>(new ByteBufferEncoder()));
|
||||
converterList.add(new CodecHttpMessageConverter<>(new StringEncoder()));
|
||||
converterList.add(new ResourceHttpMessageConverter());
|
||||
converterList.add(new CodecHttpMessageConverter<>(new Jaxb2Encoder()));
|
||||
converterList.add(new CodecHttpMessageConverter<>(new JacksonJsonEncoder()));
|
||||
}
|
||||
else {
|
||||
converterList = Arrays.asList(converters);
|
||||
}
|
||||
GenericConversionService service = new GenericConversionService();
|
||||
service.addConverter(new ReactiveStreamsToCompletableFutureConverter());
|
||||
service.addConverter(new ReactiveStreamsToRxJava1Converter());
|
||||
RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build();
|
||||
|
||||
return new ResponseEntityResultHandler(converterList, new DefaultConversionService(), resolver);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void supports() throws NoSuchMethodException {
|
||||
ResponseEntityResultHandler handler = createHandler(new StringEncoder());
|
||||
TestController controller = new TestController();
|
||||
ModelMap model = new ExtendedModelMap();
|
||||
|
||||
HandlerMethod hm = new HandlerMethod(controller, TestController.class.getMethod("responseString"));
|
||||
ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType());
|
||||
assertTrue(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(ResponseEntity.class, String.class);
|
||||
assertTrue(this.resultHandler.supports(new HandlerResult(HANDLER, null, type, model)));
|
||||
|
||||
hm = new HandlerMethod(controller, TestController.class.getMethod("responseVoid"));
|
||||
type = ResolvableType.forMethodParameter(hm.getReturnType());
|
||||
assertTrue(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
|
||||
type = ResolvableType.forClassWithGenerics(ResponseEntity.class, Void.class);
|
||||
assertTrue(this.resultHandler.supports(new HandlerResult(HANDLER, null, type, model)));
|
||||
|
||||
hm = new HandlerMethod(controller, TestController.class.getMethod("string"));
|
||||
type = ResolvableType.forMethodParameter(hm.getReturnType());
|
||||
assertFalse(handler.supports(new HandlerResult(hm, null, type, new ExtendedModelMap())));
|
||||
type = ResolvableType.forClass(Void.class);
|
||||
assertFalse(this.resultHandler.supports(new HandlerResult(HANDLER, null, type, model)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultOrder() throws Exception {
|
||||
ResponseEntityResultHandler handler = createHandler(new StringEncoder());
|
||||
assertEquals(0, handler.getOrder());
|
||||
assertEquals(0, this.resultHandler.getOrder());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jsonResponseBody() throws Exception {
|
||||
RequestedContentTypeResolver resolver = new FixedContentTypeResolver(APPLICATION_JSON_UTF8);
|
||||
HandlerResultHandler handler = createHandler(resolver, new StringEncoder(), new JacksonJsonEncoder());
|
||||
public void statusCode() throws Exception {
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(ResponseEntity.class, Void.class);
|
||||
HandlerResult result = new HandlerResult(HANDLER, ResponseEntity.noContent().build(), type);
|
||||
this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));
|
||||
|
||||
TestController controller = new TestController();
|
||||
HandlerMethod hm = new HandlerMethod(controller, controller.getClass().getMethod("responseString"));
|
||||
ResolvableType type = ResolvableType.forMethodParameter(hm.getReturnType());
|
||||
HandlerResult result = new HandlerResult(hm, ResponseEntity.ok("fooValue"), type);
|
||||
|
||||
ServerWebExchange exchange = createExchange("/foo");
|
||||
handler.handleResult(exchange, result).block();
|
||||
|
||||
assertEquals(HttpStatus.OK, this.response.getStatus());
|
||||
assertEquals(APPLICATION_JSON_UTF8, this.response.getHeaders().getContentType());
|
||||
TestSubscriber.subscribe(this.response.getBody())
|
||||
.assertValuesWith(buf -> assertEquals("\"fooValue\"",
|
||||
DataBufferTestUtils.dumpString(buf, Charset.forName("UTF-8"))));
|
||||
assertEquals(HttpStatus.NO_CONTENT, this.response.getStatus());
|
||||
assertEquals(0, this.response.getHeaders().size());
|
||||
assertNull(this.response.getBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void headers() throws Exception {
|
||||
URI location = new URI("/path");
|
||||
ResolvableType type = ResolvableType.forClassWithGenerics(ResponseEntity.class, Void.class);
|
||||
HandlerResult result = new HandlerResult(HANDLER, ResponseEntity.created(location).build(), type);
|
||||
this.resultHandler.handleResult(exchange, result).block(Duration.ofSeconds(5));
|
||||
|
||||
private ResponseEntityResultHandler createHandler(Encoder<?>... encoders) {
|
||||
return createHandler(new HeaderContentTypeResolver(), encoders);
|
||||
}
|
||||
|
||||
private ResponseEntityResultHandler createHandler(RequestedContentTypeResolver resolver,
|
||||
Encoder<?>... encoders) {
|
||||
|
||||
List<HttpMessageConverter<?>> converters = Arrays.stream(encoders)
|
||||
.map(encoder -> new CodecHttpMessageConverter<>(encoder, null))
|
||||
.collect(Collectors.toList());
|
||||
return new ResponseEntityResultHandler(converters, new DefaultConversionService(), resolver);
|
||||
}
|
||||
|
||||
private ServerWebExchange createExchange(String path) throws URISyntaxException {
|
||||
ServerHttpRequest request = new MockServerHttpRequest(HttpMethod.GET, new URI(path));
|
||||
WebSessionManager sessionManager = mock(WebSessionManager.class);
|
||||
return new DefaultServerWebExchange(request, this.response, sessionManager);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class TestController {
|
||||
|
||||
public ResponseEntity<String> responseString() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public ResponseEntity<Void> responseVoid() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public String string() {
|
||||
return null;
|
||||
}
|
||||
assertEquals(HttpStatus.CREATED, this.response.getStatus());
|
||||
assertEquals(1, this.response.getHeaders().size());
|
||||
assertEquals(location, this.response.getHeaders().getLocation());
|
||||
assertNull(this.response.getBody());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue