Properly handle Flux<?> and Flux<Object> in WebFlux
Issue: SPR-15464
This commit is contained in:
parent
a93698487e
commit
cc102c2fcd
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -42,8 +42,8 @@ public class ByteArrayEncoder extends AbstractEncoder<byte[]> {
|
|||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
Class<?> clazz = elementType.getRawClass();
|
||||
return (super.canEncode(elementType, mimeType) && byte[].class.isAssignableFrom(clazz));
|
||||
Class<?> clazz = elementType.resolve(Object.class);
|
||||
return super.canEncode(elementType, mimeType) && byte[].class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -43,8 +43,8 @@ public class ByteBufferEncoder extends AbstractEncoder<ByteBuffer> {
|
|||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
Class<?> clazz = elementType.getRawClass();
|
||||
return (super.canEncode(elementType, mimeType) && ByteBuffer.class.isAssignableFrom(clazz));
|
||||
Class<?> clazz = elementType.resolve(Object.class);
|
||||
return super.canEncode(elementType, mimeType) && ByteBuffer.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,8 +52,8 @@ public class CharSequenceEncoder extends AbstractEncoder<CharSequence> {
|
|||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
Class<?> clazz = elementType.getRawClass();
|
||||
return (super.canEncode(elementType, mimeType) && CharSequence.class.isAssignableFrom(clazz));
|
||||
Class<?> clazz = elementType.resolve(Object.class);
|
||||
return super.canEncode(elementType, mimeType) && CharSequence.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -42,8 +42,8 @@ public class DataBufferEncoder extends AbstractEncoder<DataBuffer> {
|
|||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
Class<?> clazz = elementType.getRawClass();
|
||||
return (super.canEncode(elementType, mimeType) && DataBuffer.class.isAssignableFrom(clazz));
|
||||
Class<?> clazz = elementType.resolve(Object.class);
|
||||
return super.canEncode(elementType, mimeType) && DataBuffer.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -61,7 +61,7 @@ public class ResourceEncoder extends AbstractSingleValueEncoder<Resource> {
|
|||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
Class<?> clazz = elementType.getRawClass();
|
||||
Class<?> clazz = elementType.resolve(Object.class);
|
||||
return (super.canEncode(elementType, mimeType) && Resource.class.isAssignableFrom(clazz));
|
||||
}
|
||||
|
||||
|
|
|
@ -69,9 +69,8 @@ public class ResourceRegionEncoder extends AbstractEncoder<ResourceRegion> {
|
|||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
|
||||
return super.canEncode(elementType, mimeType)
|
||||
&& ResourceRegion.class.isAssignableFrom(elementType.getRawClass());
|
||||
&& ResourceRegion.class.isAssignableFrom(elementType.resolve(Object.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -55,6 +55,9 @@ public class ByteArrayEncoderTests extends AbstractDataBufferAllocatingTestCase
|
|||
MimeTypeUtils.TEXT_PLAIN));
|
||||
assertTrue(this.encoder.canEncode(ResolvableType.forClass(byte[].class),
|
||||
MimeTypeUtils.APPLICATION_JSON));
|
||||
|
||||
// SPR-15464
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -55,6 +55,9 @@ public class ByteBufferEncoderTests extends AbstractDataBufferAllocatingTestCase
|
|||
MimeTypeUtils.TEXT_PLAIN));
|
||||
assertTrue(this.encoder.canEncode(ResolvableType.forClass(ByteBuffer.class),
|
||||
MimeTypeUtils.APPLICATION_JSON));
|
||||
|
||||
// SPR-15464
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -58,6 +58,9 @@ public class CharSequenceEncoderTests extends AbstractDataBufferAllocatingTestCa
|
|||
MimeTypeUtils.TEXT_PLAIN));
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.forClass(String.class),
|
||||
MimeTypeUtils.APPLICATION_JSON));
|
||||
|
||||
// SPR-15464
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -47,6 +47,9 @@ public class DataBufferEncoderTests extends AbstractDataBufferAllocatingTestCase
|
|||
MimeTypeUtils.TEXT_PLAIN));
|
||||
assertTrue(this.encoder.canEncode(ResolvableType.forClass(DataBuffer.class),
|
||||
MimeTypeUtils.APPLICATION_JSON));
|
||||
|
||||
// SPR-15464
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -32,6 +32,7 @@ import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase;
|
|||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -51,6 +52,9 @@ public class ResourceEncoderTests extends AbstractDataBufferAllocatingTestCase {
|
|||
MimeTypeUtils.TEXT_PLAIN));
|
||||
assertTrue(this.encoder.canEncode(ResolvableType.forClass(InputStreamResource.class),
|
||||
MimeTypeUtils.APPLICATION_JSON));
|
||||
|
||||
// SPR-15464
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -68,6 +68,9 @@ public class ResourceRegionEncoderTests extends AbstractDataBufferAllocatingTest
|
|||
assertFalse(this.encoder.canEncode(ResolvableType.forClass(Resource.class), allMimeType));
|
||||
assertTrue(this.encoder.canEncode(resourceRegion, MimeTypeUtils.APPLICATION_OCTET_STREAM));
|
||||
assertTrue(this.encoder.canEncode(resourceRegion, allMimeType));
|
||||
|
||||
// SPR-15464
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -86,7 +86,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
|
|||
@Override
|
||||
public boolean canWrite(ResolvableType elementType, MediaType mediaType) {
|
||||
return mediaType == null || MediaType.TEXT_EVENT_STREAM.includes(mediaType) ||
|
||||
ServerSentEvent.class.isAssignableFrom(elementType.getRawClass());
|
||||
ServerSentEvent.class.isAssignableFrom(elementType.resolve(Object.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -104,10 +104,10 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpMes
|
|||
|
||||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
Class<?> clazz = elementType.getRawClass();
|
||||
// Skip String: StringDecoder + "*/*" comes after
|
||||
return (!String.class.isAssignableFrom(elementType.resolve(Object.class)) &&
|
||||
this.objectMapper.canSerialize(clazz) && supportsMimeType(mimeType));
|
||||
Class<?> clazz = elementType.resolve(Object.class);
|
||||
return Object.class.equals(clazz) ||
|
||||
!String.class.isAssignableFrom(elementType.resolve(clazz)) &&
|
||||
this.objectMapper.canSerialize(clazz) && supportsMimeType(mimeType);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -55,7 +55,7 @@ public class Jaxb2XmlEncoder extends AbstractSingleValueEncoder<Object> {
|
|||
@Override
|
||||
public boolean canEncode(ResolvableType elementType, MimeType mimeType) {
|
||||
if (super.canEncode(elementType, mimeType)) {
|
||||
Class<?> outputClass = elementType.getRawClass();
|
||||
Class<?> outputClass = elementType.resolve(Object.class);
|
||||
return (outputClass.isAnnotationPresent(XmlRootElement.class) ||
|
||||
outputClass.isAnnotationPresent(XmlType.class));
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import reactor.core.publisher.Flux;
|
|||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
|
@ -52,14 +53,16 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
|
|||
|
||||
@Test
|
||||
public void canWrite() {
|
||||
|
||||
assertTrue(this.messageWriter.canWrite(forClass(Object.class), null));
|
||||
assertFalse(this.messageWriter.canWrite(forClass(Object.class), new MediaType("foo", "bar")));
|
||||
|
||||
assertTrue(this.messageWriter.canWrite(null, MediaType.TEXT_EVENT_STREAM));
|
||||
assertTrue(this.messageWriter.canWrite(forClass(ServerSentEvent.class), new MediaType("foo", "bar")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canNotWrite() {
|
||||
assertFalse(this.messageWriter.canWrite(forClass(Object.class), new MediaType("foo", "bar")));
|
||||
// SPR-15464
|
||||
assertTrue(this.messageWriter.canWrite(ResolvableType.NONE, MediaType.TEXT_EVENT_STREAM));
|
||||
assertFalse(this.messageWriter.canWrite(ResolvableType.NONE, new MediaType("foo", "bar")));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -52,6 +52,9 @@ public class Jackson2JsonEncoderTests extends AbstractDataBufferAllocatingTestCa
|
|||
ResolvableType pojoType = ResolvableType.forClass(Pojo.class);
|
||||
assertTrue(this.encoder.canEncode(pojoType, APPLICATION_JSON));
|
||||
assertTrue(this.encoder.canEncode(pojoType, null));
|
||||
|
||||
// SPR-15464
|
||||
assertTrue(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -60,6 +60,9 @@ public class Jaxb2XmlEncoderTests extends AbstractDataBufferAllocatingTestCase {
|
|||
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.forClass(getClass()),
|
||||
MediaType.APPLICATION_XML));
|
||||
|
||||
// SPR-15464
|
||||
assertFalse(this.encoder.canEncode(ResolvableType.NONE, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -24,7 +24,6 @@ import reactor.core.publisher.Mono;
|
|||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ReactiveAdapter;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
@ -79,16 +78,15 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
|
|||
|
||||
@Override
|
||||
public boolean supports(HandlerResult result) {
|
||||
if (isSupportedType(result.getReturnType())) {
|
||||
if (isSupportedType(result.getReturnType().getRawClass())) {
|
||||
return true;
|
||||
}
|
||||
ReactiveAdapter adapter = getAdapter(result);
|
||||
return adapter != null && !adapter.isNoValue() &&
|
||||
isSupportedType(result.getReturnType().getGeneric(0));
|
||||
isSupportedType(result.getReturnType().getGeneric(0).resolve(Object.class));
|
||||
}
|
||||
|
||||
private boolean isSupportedType(ResolvableType type) {
|
||||
Class<?> clazz = type.getRawClass();
|
||||
private boolean isSupportedType(Class<?> clazz) {
|
||||
return (HttpEntity.class.isAssignableFrom(clazz) && !RequestEntity.class.isAssignableFrom(clazz));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
|
@ -156,7 +156,7 @@ public class ViewResolutionResultHandler extends HandlerResultHandlerSupport
|
|||
if (adapter.isNoValue()) {
|
||||
return true;
|
||||
}
|
||||
type = result.getReturnType().getGeneric(0).getRawClass();
|
||||
type = result.getReturnType().getGeneric(0).resolve(Object.class);
|
||||
}
|
||||
return (CharSequence.class.isAssignableFrom(type) || Rendering.class.isAssignableFrom(type) ||
|
||||
Model.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type) ||
|
||||
|
|
|
@ -29,6 +29,7 @@ import java.util.concurrent.CompletableFuture;
|
|||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import rx.Completable;
|
||||
|
@ -132,6 +133,10 @@ public class ResponseEntityResultHandlerTests {
|
|||
|
||||
returnType = on(TestController.class).resolveReturnType(Completable.class);
|
||||
assertFalse(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
|
||||
// SPR-15464
|
||||
returnType = on(TestController.class).resolveReturnType(Flux.class);
|
||||
assertFalse(this.resultHandler.supports(handlerResult(value, returnType)));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -381,6 +386,7 @@ public class ResponseEntityResultHandlerTests {
|
|||
|
||||
Mono<ResponseEntity<?>> monoResponseEntityWildcard() { return null; }
|
||||
|
||||
Flux<?> fluxWildcard() { return null; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -97,6 +97,9 @@ public class ViewResolutionResultHandlerTests {
|
|||
|
||||
testSupports(on(Handler.class).annotPresent(ModelAttribute.class).resolveReturnType(Long.class));
|
||||
testDoesNotSupport(on(Handler.class).annotNotPresent(ModelAttribute.class).resolveReturnType(Long.class));
|
||||
|
||||
// SPR-15464
|
||||
testSupports(on(Handler.class).resolveReturnType(Mono.class));
|
||||
}
|
||||
|
||||
private void testSupports(MethodParameter returnType) {
|
||||
|
@ -427,6 +430,7 @@ public class ViewResolutionResultHandlerTests {
|
|||
Long longValue() { return null; }
|
||||
@ModelAttribute("myLong") Long longModelAttribute() { return null; }
|
||||
|
||||
Mono<?> monoWildcard() { return null; }
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue