Browse Source

Allow to pass hints parameter in HttpMessageReader/Writer

Issue: SPR-14557
pull/1167/head
Sebastien Deleuze 9 years ago
parent
commit
aaba53f76a
  1. 5
      spring-web-reactive/src/main/java/org/springframework/web/reactive/function/AbstractHttpMessageWriterResponse.java
  2. 6
      spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java
  3. 6
      spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ResourceResponse.java
  4. 3
      spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerSentEventResponse.java
  5. 3
      spring-web-reactive/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java
  6. 7
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
  7. 8
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java
  8. 4
      spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java
  9. 14
      spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RouterTests.java
  10. 13
      spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java
  11. 10
      spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java
  12. 24
      spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java
  13. 21
      spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java
  14. 9
      spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java
  15. 21
      spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java
  16. 7
      spring-web/src/main/java/org/springframework/web/client/reactive/ResponseExtractors.java
  17. 4
      spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java
  18. 7
      spring-web/src/main/java/org/springframework/web/client/reactive/support/RxJava1ResponseExtractors.java
  19. 15
      spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java

5
spring-web-reactive/src/main/java/org/springframework/web/reactive/function/AbstractHttpMessageWriterResponse.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.web.reactive.function;
import java.util.Collections;
import java.util.function.Supplier;
import java.util.stream.Stream;
@ -46,10 +47,10 @@ abstract class AbstractHttpMessageWriterResponse<T> extends AbstractResponse<T> @@ -46,10 +47,10 @@ abstract class AbstractHttpMessageWriterResponse<T> extends AbstractResponse<T>
MediaType contentType = exchange.getResponse().getHeaders().getContentType();
ServerHttpResponse response = exchange.getResponse();
return messageWriterStream(exchange)
.filter(messageWriter -> messageWriter.canWrite(bodyType, contentType))
.filter(messageWriter -> messageWriter.canWrite(bodyType, contentType, Collections.emptyMap()))
.findFirst()
.map(CastingUtils::cast)
.map(messageWriter -> messageWriter.write(body, bodyType, contentType, response))
.map(messageWriter -> messageWriter.write(body, bodyType, contentType, response, Collections.emptyMap()))
.orElseGet(() -> {
response.setStatusCode(HttpStatus.NOT_ACCEPTABLE);
return response.setComplete();

6
spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java

@ -173,13 +173,13 @@ class DefaultRequest implements Request { @@ -173,13 +173,13 @@ class DefaultRequest implements Request {
@Override
public <T> Flux<T> convertTo(Class<? extends T> aClass) {
ResolvableType elementType = ResolvableType.forClass(aClass);
return convertTo(aClass, reader -> reader.read(elementType, request()));
return convertTo(aClass, reader -> reader.read(elementType, request(), Collections.emptyMap()));
}
@Override
public <T> Mono<T> convertToMono(Class<? extends T> aClass) {
ResolvableType elementType = ResolvableType.forClass(aClass);
return convertTo(aClass, reader -> reader.readMono(elementType, request()));
return convertTo(aClass, reader -> reader.readMono(elementType, request(), Collections.emptyMap()));
}
private <T, S extends Publisher<T>> S convertTo(Class<? extends T> targetClass,
@ -187,7 +187,7 @@ class DefaultRequest implements Request { @@ -187,7 +187,7 @@ class DefaultRequest implements Request {
ResolvableType elementType = ResolvableType.forClass(targetClass);
MediaType contentType = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM);
return messageReaderStream(exchange)
.filter(r -> r.canRead(elementType, contentType))
.filter(r -> r.canRead(elementType, contentType, Collections.emptyMap()))
.findFirst()
.map(CastingUtils::<T>cast)
.map(readerFunction)

6
spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ResourceResponse.java

@ -16,6 +16,8 @@ @@ -16,6 +16,8 @@
package org.springframework.web.reactive.function;
import java.util.Collections;
import reactor.core.publisher.Mono;
import org.springframework.core.ResolvableType;
@ -48,8 +50,8 @@ class ResourceResponse extends AbstractResponse<Resource> { @@ -48,8 +50,8 @@ class ResourceResponse extends AbstractResponse<Resource> {
@Override
public Mono<Void> writeTo(ServerWebExchange exchange) {
writeStatusAndHeaders(exchange);
return this.messageWriter
.write(Mono.just(this.resource), RESOURCE_TYPE, null, exchange.getResponse());
return this.messageWriter.write(Mono.just(this.resource), RESOURCE_TYPE, null,
exchange.getResponse(), Collections.emptyMap());
}
}

3
spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerSentEventResponse.java

@ -74,7 +74,8 @@ class ServerSentEventResponse<T extends Publisher<?>> extends AbstractResponse<T @@ -74,7 +74,8 @@ class ServerSentEventResponse<T extends Publisher<?>> extends AbstractResponse<T
@Override
public Mono<Void> writeTo(ServerWebExchange exchange) {
writeStatusAndHeaders(exchange);
return this.messageWriter.write(this.eventsPublisher, this.eventType, null, exchange.getResponse());
return this.messageWriter.write(this.eventsPublisher, this.eventType, null,
exchange.getResponse(), Collections.emptyMap());
}
}

3
spring-web-reactive/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java

@ -21,6 +21,7 @@ import java.net.URLDecoder; @@ -21,6 +21,7 @@ import java.net.URLDecoder;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -333,7 +334,7 @@ public class ResourceWebHandler @@ -333,7 +334,7 @@ public class ResourceWebHandler
setHeaders(exchange, resource, mediaType);
return this.resourceHttpMessageWriter.write(Mono.just(resource),
ResolvableType.forClass(Resource.class), mediaType, exchange.getResponse());
ResolvableType.forClass(Resource.class), mediaType, exchange.getResponse(), Collections.emptyMap());
}
catch (IOException ex) {
return Mono.error(ex);

7
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.web.reactive.result.method.annotation;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -129,9 +130,9 @@ public abstract class AbstractMessageReaderArgumentResolver { @@ -129,9 +130,9 @@ public abstract class AbstractMessageReaderArgumentResolver {
}
for (HttpMessageReader<?> reader : getMessageReaders()) {
if (reader.canRead(elementType, mediaType)) {
if (reader.canRead(elementType, mediaType, Collections.emptyMap())) {
if (adapter != null && adapter.getDescriptor().isMultiValue()) {
Flux<?> flux = reader.read(elementType, request)
Flux<?> flux = reader.read(elementType, request, Collections.emptyMap())
.onErrorResumeWith(ex -> Flux.error(getReadError(ex, bodyParameter)));
if (checkRequired(adapter, isBodyRequired)) {
flux = flux.switchIfEmpty(Flux.error(getRequiredBodyError(bodyParameter)));
@ -142,7 +143,7 @@ public abstract class AbstractMessageReaderArgumentResolver { @@ -142,7 +143,7 @@ public abstract class AbstractMessageReaderArgumentResolver {
return Mono.just(adapter.fromPublisher(flux));
}
else {
Mono<?> mono = reader.readMono(elementType, request)
Mono<?> mono = reader.readMono(elementType, request, Collections.emptyMap())
.otherwise(ex -> Mono.error(getReadError(ex, bodyParameter)));
if (checkRequired(adapter, isBodyRequired)) {
mono = mono.otherwiseIfEmpty(Mono.error(getRequiredBodyError(bodyParameter)));

8
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
*/
package org.springframework.web.reactive.result.method.annotation;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@ -120,9 +121,10 @@ public abstract class AbstractMessageWriterResultHandler extends ContentNegotiat @@ -120,9 +121,10 @@ public abstract class AbstractMessageWriterResultHandler extends ContentNegotiat
if (bestMediaType != null) {
for (HttpMessageWriter<?> messageWriter : getMessageWriters()) {
if (messageWriter.canWrite(elementType, bestMediaType)) {
if (messageWriter.canWrite(elementType, bestMediaType, Collections.emptyMap())) {
ServerHttpResponse response = exchange.getResponse();
return messageWriter.write((Publisher) publisher, elementType, bestMediaType, response);
return messageWriter.write((Publisher) publisher, elementType,
bestMediaType, response, Collections.emptyMap());
}
}
}
@ -132,7 +134,7 @@ public abstract class AbstractMessageWriterResultHandler extends ContentNegotiat @@ -132,7 +134,7 @@ public abstract class AbstractMessageWriterResultHandler extends ContentNegotiat
private List<MediaType> getProducibleMediaTypes(ResolvableType elementType) {
return getMessageWriters().stream()
.filter(converter -> converter.canWrite(elementType, null))
.filter(converter -> converter.canWrite(elementType, null, Collections.emptyMap()))
.flatMap(converter -> converter.getWritableMediaTypes().stream())
.collect(Collectors.toList());
}

4
spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java

@ -250,7 +250,7 @@ public class WebReactiveConfigurationTests { @@ -250,7 +250,7 @@ public class WebReactiveConfigurationTests {
private void assertHasMessageReader(List<HttpMessageReader<?>> readers, Class<?> clazz, MediaType mediaType) {
ResolvableType type = ResolvableType.forClass(clazz);
assertTrue(readers.stream()
.filter(c -> mediaType == null || c.canRead(type, mediaType))
.filter(c -> mediaType == null || c.canRead(type, mediaType, Collections.emptyMap()))
.findAny()
.isPresent());
}
@ -258,7 +258,7 @@ public class WebReactiveConfigurationTests { @@ -258,7 +258,7 @@ public class WebReactiveConfigurationTests {
private void assertHasMessageWriter(List<HttpMessageWriter<?>> writers, Class<?> clazz, MediaType mediaType) {
ResolvableType type = ResolvableType.forClass(clazz);
assertTrue(writers.stream()
.filter(c -> mediaType == null || c.canWrite(type, mediaType))
.filter(c -> mediaType == null || c.canWrite(type, mediaType, Collections.emptyMap()))
.findAny()
.isPresent());
}

14
spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RouterTests.java

@ -18,6 +18,7 @@ package org.springframework.web.reactive.function; @@ -18,6 +18,7 @@ package org.springframework.web.reactive.function;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.junit.Test;
@ -163,7 +164,7 @@ public class RouterTests { @@ -163,7 +164,7 @@ public class RouterTests {
private static class DummyMessageWriter implements HttpMessageWriter<Object> {
@Override
public boolean canWrite(ResolvableType type, MediaType mediaType) {
public boolean canWrite(ResolvableType type, MediaType mediaType, Map<String, Object> hints) {
return false;
}
@ -175,7 +176,8 @@ public class RouterTests { @@ -175,7 +176,8 @@ public class RouterTests {
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType type,
MediaType contentType,
ReactiveHttpOutputMessage outputMessage) {
ReactiveHttpOutputMessage outputMessage,
Map<String, Object> hints) {
return Mono.empty();
}
}
@ -183,7 +185,7 @@ public class RouterTests { @@ -183,7 +185,7 @@ public class RouterTests {
private static class DummyMessageReader implements HttpMessageReader<Object> {
@Override
public boolean canRead(ResolvableType type, MediaType mediaType) {
public boolean canRead(ResolvableType type, MediaType mediaType, Map<String, Object> hints) {
return false;
}
@ -193,12 +195,14 @@ public class RouterTests { @@ -193,12 +195,14 @@ public class RouterTests {
}
@Override
public Flux<Object> read(ResolvableType type, ReactiveHttpInputMessage inputMessage) {
public Flux<Object> read(ResolvableType type, ReactiveHttpInputMessage inputMessage,
Map<String, Object> hints) {
return Flux.empty();
}
@Override
public Mono<Object> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage) {
public Mono<Object> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage,
Map<String, Object> hints) {
return Mono.empty();
}
}

13
spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java

@ -18,6 +18,7 @@ package org.springframework.http.codec; @@ -18,6 +18,7 @@ package org.springframework.http.codec;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -55,8 +56,8 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> { @@ -55,8 +56,8 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
@Override
public boolean canRead(ResolvableType type, MediaType mediaType) {
return this.decoder != null && this.decoder.canDecode(type, mediaType);
public boolean canRead(ResolvableType type, MediaType mediaType, Map<String, Object> hints) {
return this.decoder != null && this.decoder.canDecode(type, mediaType, hints);
}
@Override
@ -66,21 +67,21 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> { @@ -66,21 +67,21 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
@Override
public Flux<T> read(ResolvableType type, ReactiveHttpInputMessage inputMessage) {
public Flux<T> read(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) {
if (this.decoder == null) {
return Flux.error(new IllegalStateException("No decoder set"));
}
MediaType contentType = getContentType(inputMessage);
return this.decoder.decode(inputMessage.getBody(), type, contentType);
return this.decoder.decode(inputMessage.getBody(), type, contentType, hints);
}
@Override
public Mono<T> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage) {
public Mono<T> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) {
if (this.decoder == null) {
return Mono.error(new IllegalStateException("No decoder set"));
}
MediaType contentType = getContentType(inputMessage);
return this.decoder.decodeToMono(inputMessage.getBody(), type, contentType);
return this.decoder.decodeToMono(inputMessage.getBody(), type, contentType, hints);
}
private MediaType getContentType(ReactiveHttpInputMessage inputMessage) {

10
spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java

@ -18,6 +18,7 @@ package org.springframework.http.codec; @@ -18,6 +18,7 @@ package org.springframework.http.codec;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Flux;
@ -59,8 +60,8 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -59,8 +60,8 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
@Override
public boolean canWrite(ResolvableType type, MediaType mediaType) {
return this.encoder != null && this.encoder.canEncode(type, mediaType);
public boolean canWrite(ResolvableType type, MediaType mediaType, Map<String, Object> hints) {
return this.encoder != null && this.encoder.canEncode(type, mediaType, hints);
}
@Override
@ -71,7 +72,8 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -71,7 +72,8 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
@Override
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType type,
MediaType contentType, ReactiveHttpOutputMessage outputMessage) {
MediaType contentType, ReactiveHttpOutputMessage outputMessage,
Map<String, Object> hints) {
if (this.encoder == null) {
return Mono.error(new IllegalStateException("No decoder set"));
@ -99,7 +101,7 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -99,7 +101,7 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
}
DataBufferFactory bufferFactory = outputMessage.bufferFactory();
Flux<DataBuffer> body = this.encoder.encode(inputStream, bufferFactory, type, contentType);
Flux<DataBuffer> body = this.encoder.encode(inputStream, bufferFactory, type, contentType, hints);
return outputMessage.writeWith(body);
}

24
spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java

@ -16,7 +16,9 @@ @@ -16,7 +16,9 @@
package org.springframework.http.codec;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@ -31,6 +33,7 @@ import org.springframework.http.ReactiveHttpInputMessage; @@ -31,6 +33,7 @@ import org.springframework.http.ReactiveHttpInputMessage;
*
* @author Rossen Stoyanchev
* @author Arjen Poutsma
* @author Sebastien Deleuze
* @since 5.0
*/
public interface HttpMessageReader<T> {
@ -40,15 +43,10 @@ public interface HttpMessageReader<T> { @@ -40,15 +43,10 @@ public interface HttpMessageReader<T> {
* @param type the type to test for readability
* @param mediaType the media type to read, can be {@code null} if not specified.
* Typically the value of a {@code Content-Type} header.
* @param hints additional information about how to do read
* @return {@code true} if readable; {@code false} otherwise
*/
boolean canRead(ResolvableType type, MediaType mediaType);
/**
* Return the list of {@link MediaType} objects that can be read by this converter.
* @return the list of supported readable media types
*/
List<MediaType> getReadableMediaTypes();
boolean canRead(ResolvableType type, MediaType mediaType, Map<String, Object> hints);
/**
* Read a {@link Flux} of the given type form the given input message, and returns it.
@ -56,9 +54,10 @@ public interface HttpMessageReader<T> { @@ -56,9 +54,10 @@ public interface HttpMessageReader<T> {
* passed to the {@link #canRead canRead} method of this interface, which must have
* returned {@code true}.
* @param inputMessage the HTTP input message to read from
* @param hints additional information about how to do read
* @return the converted {@link Flux} of elements
*/
Flux<T> read(ResolvableType type, ReactiveHttpInputMessage inputMessage);
Flux<T> read(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints);
/**
* Read a {@link Mono} of the given type form the given input message, and returns it.
@ -66,8 +65,15 @@ public interface HttpMessageReader<T> { @@ -66,8 +65,15 @@ public interface HttpMessageReader<T> {
* passed to the {@link #canRead canRead} method of this interface, which must have
* returned {@code true}.
* @param inputMessage the HTTP input message to read from
* @param hints additional information about how to do read
* @return the converted {@link Mono} of object
*/
Mono<T> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage);
Mono<T> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints);
/**
* Return the list of {@link MediaType} objects that can be read by this converter.
* @return the list of supported readable media types
*/
List<MediaType> getReadableMediaTypes();
}

21
spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java

@ -16,7 +16,9 @@ @@ -16,7 +16,9 @@
package org.springframework.http.codec;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
@ -31,6 +33,7 @@ import org.springframework.http.ReactiveHttpOutputMessage; @@ -31,6 +33,7 @@ import org.springframework.http.ReactiveHttpOutputMessage;
*
* @author Rossen Stoyanchev
* @author Arjen Poutsma
* @author Sebastien Deleuze
* @since 5.0
*/
public interface HttpMessageWriter<T> {
@ -40,15 +43,10 @@ public interface HttpMessageWriter<T> { @@ -40,15 +43,10 @@ public interface HttpMessageWriter<T> {
* @param type the class to test for writability
* @param mediaType the media type to write, can be {@code null} if not specified.
* Typically the value of an {@code Accept} header.
* @param hints additional information about how to do write
* @return {@code true} if writable; {@code false} otherwise
*/
boolean canWrite(ResolvableType type, MediaType mediaType);
/**
* Return the list of {@link MediaType} objects that can be written by this converter.
* @return the list of supported readable media types
*/
List<MediaType> getWritableMediaTypes();
boolean canWrite(ResolvableType type, MediaType mediaType, Map<String, Object> hints);
/**
* Write an given object to the given output message.
@ -57,9 +55,16 @@ public interface HttpMessageWriter<T> { @@ -57,9 +55,16 @@ public interface HttpMessageWriter<T> {
* @param contentType the content type to use when writing. May be {@code null} to
* indicate that the default content type of the converter must be used.
* @param outputMessage the message to write to
* @param hints additional information about how to do write
* @return the converted {@link Mono} of object
*/
Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType type,
MediaType contentType, ReactiveHttpOutputMessage outputMessage);
MediaType contentType, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints);
/**
* Return the list of {@link MediaType} objects that can be written by this converter.
* @return the list of supported readable media types
*/
List<MediaType> getWritableMediaTypes();
}

9
spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java

@ -18,6 +18,7 @@ package org.springframework.http.codec; @@ -18,6 +18,7 @@ package org.springframework.http.codec;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import org.reactivestreams.Publisher;
@ -59,14 +60,14 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource @@ -59,14 +60,14 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource
@Override
public Mono<Void> write(Publisher<? extends Resource> inputStream, ResolvableType type,
MediaType contentType, ReactiveHttpOutputMessage outputMessage) {
MediaType contentType, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) {
return Mono.from(Flux.from(inputStream).
take(1).
concatMap(resource -> {
HttpHeaders headers = outputMessage.getHeaders();
addHeaders(headers, resource, contentType);
return writeContent(resource, type, outputMessage);
return writeContent(resource, type, outputMessage, hints);
}));
}
@ -84,7 +85,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource @@ -84,7 +85,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource
}
}
private Mono<Void> writeContent(Resource resource, ResolvableType type, ReactiveHttpOutputMessage outputMessage) {
private Mono<Void> writeContent(Resource resource, ResolvableType type, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) {
if (outputMessage instanceof ZeroCopyHttpOutputMessage) {
Optional<File> file = getFile(resource);
if (file.isPresent()) {
@ -97,7 +98,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource @@ -97,7 +98,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter<Resource
// non-zero copy fallback, using ResourceEncoder
return super.write(Mono.just(resource), type,
outputMessage.getHeaders().getContentType(), outputMessage);
outputMessage.getHeaders().getContentType(), outputMessage, hints);
}
private static Optional<Long> contentLength(Resource resource) {

21
spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java

@ -19,6 +19,7 @@ package org.springframework.http.codec; @@ -19,6 +19,7 @@ package org.springframework.http.codec;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.reactivestreams.Publisher;
@ -61,7 +62,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec @@ -61,7 +62,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
}
@Override
public boolean canWrite(ResolvableType type, MediaType mediaType) {
public boolean canWrite(ResolvableType type, MediaType mediaType, Map<String, Object> hints) {
return mediaType == null || TEXT_EVENT_STREAM.isCompatibleWith(mediaType);
}
@ -71,19 +72,19 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec @@ -71,19 +72,19 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
}
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType type,
MediaType contentType, ReactiveHttpOutputMessage outputMessage) {
public Mono<Void> write(Publisher<?> inputStream, ResolvableType type, MediaType contentType,
ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) {
outputMessage.getHeaders().setContentType(TEXT_EVENT_STREAM);
DataBufferFactory bufferFactory = outputMessage.bufferFactory();
Flux<Publisher<DataBuffer>> body = encode(inputStream, bufferFactory, type);
Flux<Publisher<DataBuffer>> body = encode(inputStream, bufferFactory, type, hints);
return outputMessage.writeAndFlushWith(body);
}
private Flux<Publisher<DataBuffer>> encode(Publisher<?> inputStream,
DataBufferFactory bufferFactory, ResolvableType type) {
private Flux<Publisher<DataBuffer>> encode(Publisher<?> inputStream, DataBufferFactory bufferFactory,
ResolvableType type, Map<String, Object> hints) {
return Flux.from(inputStream)
.map(o -> toSseEvent(o, type))
@ -105,7 +106,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec @@ -105,7 +106,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
return Flux.empty();
}
else {
return applyEncoder(data, bufferFactory);
return applyEncoder(data, bufferFactory, hints);
}
}).orElse(Flux.empty());
@ -129,14 +130,14 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec @@ -129,14 +130,14 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
}
@SuppressWarnings("unchecked")
private <T> Flux<DataBuffer> applyEncoder(Object data, DataBufferFactory bufferFactory) {
private <T> Flux<DataBuffer> applyEncoder(Object data, DataBufferFactory bufferFactory, Map<String, Object> hints) {
ResolvableType elementType = ResolvableType.forClass(data.getClass());
Optional<Encoder<?>> encoder = dataEncoders
.stream()
.filter(e -> e.canEncode(elementType, MimeTypeUtils.APPLICATION_JSON))
.filter(e -> e.canEncode(elementType, MimeTypeUtils.APPLICATION_JSON, Collections.emptyMap()))
.findFirst();
return ((Encoder<T>) encoder.orElseThrow(() -> new CodecException("No suitable encoder found!")))
.encode(Mono.just((T) data), bufferFactory, elementType, MimeTypeUtils.APPLICATION_JSON)
.encode(Mono.just((T) data), bufferFactory, elementType, MimeTypeUtils.APPLICATION_JSON, hints)
.concatWith(encodeString("\n", bufferFactory));
}

7
spring-web/src/main/java/org/springframework/web/client/reactive/ResponseExtractors.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.web.client.reactive;
import java.util.Collections;
import java.util.List;
import reactor.core.publisher.Flux;
@ -179,7 +180,7 @@ public class ResponseExtractors { @@ -179,7 +180,7 @@ public class ResponseExtractors {
MediaType contentType = response.getHeaders().getContentType();
HttpMessageReader<?> reader = resolveMessageReader(messageReaders, responseType, contentType);
return (Flux<T>) reader.read(responseType, response);
return (Flux<T>) reader.read(responseType, response, Collections.emptyMap());
}
@SuppressWarnings("unchecked")
@ -188,14 +189,14 @@ public class ResponseExtractors { @@ -188,14 +189,14 @@ public class ResponseExtractors {
MediaType contentType = response.getHeaders().getContentType();
HttpMessageReader<?> reader = resolveMessageReader(messageReaders, responseType, contentType);
return (Mono<T>) reader.readMono(responseType, response);
return (Mono<T>) reader.readMono(responseType, response, Collections.emptyMap());
}
protected static HttpMessageReader<?> resolveMessageReader(List<HttpMessageReader<?>> messageReaders,
ResolvableType responseType, MediaType contentType) {
return messageReaders.stream()
.filter(e -> e.canRead(responseType, contentType))
.filter(e -> e.canRead(responseType, contentType, Collections.emptyMap()))
.findFirst()
.orElseThrow(() ->
new WebClientException(

4
spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java

@ -291,13 +291,13 @@ public final class WebClient { @@ -291,13 +291,13 @@ public final class WebClient {
"Could not encode request body of type '" + contentType
+ "' with target type '" + requestType.toString() + "'"));
}
return messageWriter.get().write((Publisher) content, requestType, contentType, request);
return messageWriter.get().write((Publisher) content, requestType, contentType, request, Collections.emptyMap());
}
protected Optional<HttpMessageWriter<?>> resolveWriter(List<HttpMessageWriter<?>> messageWriters,
ResolvableType type, MediaType mediaType) {
return messageWriters.stream().filter(e -> e.canWrite(type, mediaType)).findFirst();
return messageWriters.stream().filter(e -> e.canWrite(type, mediaType, Collections.emptyMap())).findFirst();
}
}

7
spring-web/src/main/java/org/springframework/web/client/reactive/support/RxJava1ResponseExtractors.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.web.client.reactive.support;
import java.util.Collections;
import java.util.List;
import reactor.adapter.RxJava1Adapter;
@ -193,7 +194,7 @@ public class RxJava1ResponseExtractors { @@ -193,7 +194,7 @@ public class RxJava1ResponseExtractors {
MediaType contentType = response.getHeaders().getContentType();
HttpMessageReader<?> converter = resolveMessageReader(messageReaders, responseType, contentType);
return (Flux<T>) converter.read(responseType, response);
return (Flux<T>) converter.read(responseType, response, Collections.emptyMap());
}
@SuppressWarnings("unchecked")
@ -202,14 +203,14 @@ public class RxJava1ResponseExtractors { @@ -202,14 +203,14 @@ public class RxJava1ResponseExtractors {
MediaType contentType = response.getHeaders().getContentType();
HttpMessageReader<?> converter = resolveMessageReader(messageReaders, responseType, contentType);
return (Mono<T>) converter.readMono(responseType, response);
return (Mono<T>) converter.readMono(responseType, response, Collections.emptyMap());
}
protected static HttpMessageReader<?> resolveMessageReader(List<HttpMessageReader<?>> messageReaders,
ResolvableType responseType, MediaType contentType) {
return messageReaders.stream()
.filter(e -> e.canRead(responseType, contentType))
.filter(e -> e.canRead(responseType, contentType, Collections.emptyMap()))
.findFirst()
.orElseThrow(() ->
new WebClientException(

15
spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java

@ -46,19 +46,20 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll @@ -46,19 +46,20 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
@Test
public void nullMimeType() {
assertTrue(messageWriter.canWrite(ResolvableType.forClass(Object.class), null));
assertTrue(messageWriter.canWrite(ResolvableType.forClass(Object.class), null,
Collections.emptyMap()));
}
@Test
public void unsupportedMimeType() {
assertFalse(messageWriter.canWrite(ResolvableType.forClass(Object.class),
new MediaType("foo", "bar")));
new MediaType("foo", "bar"), Collections.emptyMap()));
}
@Test
public void supportedMimeType() {
assertTrue(messageWriter.canWrite(ResolvableType.forClass(Object.class),
new MediaType("text", "event-stream")));
new MediaType("text", "event-stream"), Collections.emptyMap()));
}
@Test
@ -69,7 +70,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll @@ -69,7 +70,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
Mono<ServerSentEvent<String>> source = Mono.just(event);
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(ServerSentEvent.class),
new MediaType("text", "event-stream"), outputMessage);
new MediaType("text", "event-stream"), outputMessage, Collections.emptyMap());
Publisher<Publisher<DataBuffer>> result = outputMessage.getBodyWithFlush();
TestSubscriber.subscribe(result).
@ -89,7 +90,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll @@ -89,7 +90,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
Flux<String> source = Flux.just("foo", "bar");
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(String.class),
new MediaType("text", "event-stream"), outputMessage);
new MediaType("text", "event-stream"), outputMessage, Collections.emptyMap());
Publisher<Publisher<DataBuffer>> result = outputMessage.getBodyWithFlush();
TestSubscriber.subscribe(result).
@ -112,7 +113,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll @@ -112,7 +113,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
Flux<String> source = Flux.just("foo\nbar", "foo\nbaz");
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(String.class),
new MediaType("text", "event-stream"), outputMessage);
new MediaType("text", "event-stream"), outputMessage, Collections.emptyMap());
Publisher<Publisher<DataBuffer>> result = outputMessage.getBodyWithFlush();
TestSubscriber.subscribe(result).
@ -136,7 +137,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll @@ -136,7 +137,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll
new Pojo("foofoofoo", "barbarbar"));
MockServerHttpResponse outputMessage = new MockServerHttpResponse();
messageWriter.write(source, ResolvableType.forClass(Pojo.class),
new MediaType("text", "event-stream"), outputMessage);
new MediaType("text", "event-stream"), outputMessage, Collections.emptyMap());
Publisher<Publisher<DataBuffer>> result = outputMessage.getBodyWithFlush();
TestSubscriber.subscribe(result).

Loading…
Cancel
Save