From aaba53f76a6c59166eda1215c8524db33173648c Mon Sep 17 00:00:00 2001 From: Sebastien Deleuze Date: Mon, 12 Sep 2016 11:08:14 +0200 Subject: [PATCH] Allow to pass hints parameter in HttpMessageReader/Writer Issue: SPR-14557 --- .../AbstractHttpMessageWriterResponse.java | 5 ++-- .../web/reactive/function/DefaultRequest.java | 6 ++--- .../reactive/function/ResourceResponse.java | 6 +++-- .../function/ServerSentEventResponse.java | 3 ++- .../reactive/resource/ResourceWebHandler.java | 3 ++- ...AbstractMessageReaderArgumentResolver.java | 7 +++--- .../AbstractMessageWriterResultHandler.java | 8 ++++--- .../config/WebReactiveConfigurationTests.java | 4 ++-- .../web/reactive/function/RouterTests.java | 14 +++++++---- .../http/codec/DecoderHttpMessageReader.java | 13 +++++----- .../http/codec/EncoderHttpMessageWriter.java | 10 ++++---- .../http/codec/HttpMessageReader.java | 24 ++++++++++++------- .../http/codec/HttpMessageWriter.java | 21 +++++++++------- .../http/codec/ResourceHttpMessageWriter.java | 9 +++---- .../ServerSentEventHttpMessageWriter.java | 21 ++++++++-------- .../client/reactive/ResponseExtractors.java | 7 +++--- .../web/client/reactive/WebClient.java | 4 ++-- .../support/RxJava1ResponseExtractors.java | 7 +++--- ...ServerSentEventHttpMessageWriterTests.java | 15 ++++++------ 19 files changed, 109 insertions(+), 78 deletions(-) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/AbstractHttpMessageWriterResponse.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/AbstractHttpMessageWriterResponse.java index cd18b4bf634..02c86b73b00 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/AbstractHttpMessageWriterResponse.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/AbstractHttpMessageWriterResponse.java @@ -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 extends AbstractResponse 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(); diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java index f6c57883526..fdbd9e04f1d 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java @@ -173,13 +173,13 @@ class DefaultRequest implements Request { @Override public Flux convertTo(Class 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 Mono convertToMono(Class 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 > S convertTo(Class targetClass, @@ -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::cast) .map(readerFunction) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ResourceResponse.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ResourceResponse.java index 43a28c9ed30..383d4e6e26b 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ResourceResponse.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ResourceResponse.java @@ -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 { @Override public Mono 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()); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerSentEventResponse.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerSentEventResponse.java index 7a6bc1b036a..66a8dc79067 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerSentEventResponse.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerSentEventResponse.java @@ -74,7 +74,8 @@ class ServerSentEventResponse> extends AbstractResponse 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()); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java index d79a02d3bb9..e27a5d117e6 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/resource/ResourceWebHandler.java @@ -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 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); diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java index 748e7129603..5f989412868 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java @@ -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 { } 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 { 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))); diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java index 5f05bd7ba64..e4d6bfc9f77 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java @@ -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 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 private List 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()); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java index cca0195aebf..5023f9cd5d4 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/config/WebReactiveConfigurationTests.java @@ -250,7 +250,7 @@ public class WebReactiveConfigurationTests { private void assertHasMessageReader(List> 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 { private void assertHasMessageWriter(List> 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()); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RouterTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RouterTests.java index 4a95b8ba91c..8ddd11961eb 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RouterTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RouterTests.java @@ -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 { private static class DummyMessageWriter implements HttpMessageWriter { @Override - public boolean canWrite(ResolvableType type, MediaType mediaType) { + public boolean canWrite(ResolvableType type, MediaType mediaType, Map hints) { return false; } @@ -175,7 +176,8 @@ public class RouterTests { @Override public Mono write(Publisher inputStream, ResolvableType type, MediaType contentType, - ReactiveHttpOutputMessage outputMessage) { + ReactiveHttpOutputMessage outputMessage, + Map hints) { return Mono.empty(); } } @@ -183,7 +185,7 @@ public class RouterTests { private static class DummyMessageReader implements HttpMessageReader { @Override - public boolean canRead(ResolvableType type, MediaType mediaType) { + public boolean canRead(ResolvableType type, MediaType mediaType, Map hints) { return false; } @@ -193,12 +195,14 @@ public class RouterTests { } @Override - public Flux read(ResolvableType type, ReactiveHttpInputMessage inputMessage) { + public Flux read(ResolvableType type, ReactiveHttpInputMessage inputMessage, + Map hints) { return Flux.empty(); } @Override - public Mono readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage) { + public Mono readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage, + Map hints) { return Mono.empty(); } } diff --git a/spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java index 102f7471a71..38be3457282 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java @@ -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 implements HttpMessageReader { @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 hints) { + return this.decoder != null && this.decoder.canDecode(type, mediaType, hints); } @Override @@ -66,21 +67,21 @@ public class DecoderHttpMessageReader implements HttpMessageReader { @Override - public Flux read(ResolvableType type, ReactiveHttpInputMessage inputMessage) { + public Flux read(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map 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 readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage) { + public Mono readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map 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) { diff --git a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java index 2a57ce44bb0..2ffce181af2 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java @@ -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 implements HttpMessageWriter { @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 hints) { + return this.encoder != null && this.encoder.canEncode(type, mediaType, hints); } @Override @@ -71,7 +72,8 @@ public class EncoderHttpMessageWriter implements HttpMessageWriter { @Override public Mono write(Publisher inputStream, ResolvableType type, - MediaType contentType, ReactiveHttpOutputMessage outputMessage) { + MediaType contentType, ReactiveHttpOutputMessage outputMessage, + Map hints) { if (this.encoder == null) { return Mono.error(new IllegalStateException("No decoder set")); @@ -99,7 +101,7 @@ public class EncoderHttpMessageWriter implements HttpMessageWriter { } DataBufferFactory bufferFactory = outputMessage.bufferFactory(); - Flux body = this.encoder.encode(inputStream, bufferFactory, type, contentType); + Flux body = this.encoder.encode(inputStream, bufferFactory, type, contentType, hints); return outputMessage.writeWith(body); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java b/spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java index 0ef5820bb5f..7fb7e76a186 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java +++ b/spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java @@ -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; * * @author Rossen Stoyanchev * @author Arjen Poutsma + * @author Sebastien Deleuze * @since 5.0 */ public interface HttpMessageReader { @@ -40,15 +43,10 @@ public interface HttpMessageReader { * @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 getReadableMediaTypes(); + boolean canRead(ResolvableType type, MediaType mediaType, Map hints); /** * Read a {@link Flux} of the given type form the given input message, and returns it. @@ -56,9 +54,10 @@ public interface HttpMessageReader { * 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 read(ResolvableType type, ReactiveHttpInputMessage inputMessage); + Flux read(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map hints); /** * Read a {@link Mono} of the given type form the given input message, and returns it. @@ -66,8 +65,15 @@ public interface HttpMessageReader { * 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 readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage); + Mono readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage, Map hints); + + /** + * Return the list of {@link MediaType} objects that can be read by this converter. + * @return the list of supported readable media types + */ + List getReadableMediaTypes(); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java index e5dad98b0c0..900c2af85aa 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java @@ -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; * * @author Rossen Stoyanchev * @author Arjen Poutsma + * @author Sebastien Deleuze * @since 5.0 */ public interface HttpMessageWriter { @@ -40,15 +43,10 @@ public interface HttpMessageWriter { * @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 getWritableMediaTypes(); + boolean canWrite(ResolvableType type, MediaType mediaType, Map hints); /** * Write an given object to the given output message. @@ -57,9 +55,16 @@ public interface HttpMessageWriter { * @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 write(Publisher inputStream, ResolvableType type, - MediaType contentType, ReactiveHttpOutputMessage outputMessage); + MediaType contentType, ReactiveHttpOutputMessage outputMessage, Map hints); + + /** + * Return the list of {@link MediaType} objects that can be written by this converter. + * @return the list of supported readable media types + */ + List getWritableMediaTypes(); } diff --git a/spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java index 9b2d8dd9e21..a488cbf2a0b 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java @@ -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 write(Publisher inputStream, ResolvableType type, - MediaType contentType, ReactiveHttpOutputMessage outputMessage) { + MediaType contentType, ReactiveHttpOutputMessage outputMessage, Map 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 writeContent(Resource resource, ResolvableType type, ReactiveHttpOutputMessage outputMessage) { + private Mono writeContent(Resource resource, ResolvableType type, ReactiveHttpOutputMessage outputMessage, Map hints) { if (outputMessage instanceof ZeroCopyHttpOutputMessage) { Optional file = getFile(resource); if (file.isPresent()) { @@ -97,7 +98,7 @@ public class ResourceHttpMessageWriter extends EncoderHttpMessageWriter contentLength(Resource resource) { diff --git a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java index ceeabd75e7b..d54679d0740 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java @@ -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 hints) { return mediaType == null || TEXT_EVENT_STREAM.isCompatibleWith(mediaType); } @@ -71,19 +72,19 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter write(Publisher inputStream, ResolvableType type, - MediaType contentType, ReactiveHttpOutputMessage outputMessage) { + public Mono write(Publisher inputStream, ResolvableType type, MediaType contentType, + ReactiveHttpOutputMessage outputMessage, Map hints) { outputMessage.getHeaders().setContentType(TEXT_EVENT_STREAM); DataBufferFactory bufferFactory = outputMessage.bufferFactory(); - Flux> body = encode(inputStream, bufferFactory, type); + Flux> body = encode(inputStream, bufferFactory, type, hints); return outputMessage.writeAndFlushWith(body); } - private Flux> encode(Publisher inputStream, - DataBufferFactory bufferFactory, ResolvableType type) { + private Flux> encode(Publisher inputStream, DataBufferFactory bufferFactory, + ResolvableType type, Map hints) { return Flux.from(inputStream) .map(o -> toSseEvent(o, type)) @@ -105,7 +106,7 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter Flux applyEncoder(Object data, DataBufferFactory bufferFactory) { + private Flux applyEncoder(Object data, DataBufferFactory bufferFactory, Map hints) { ResolvableType elementType = ResolvableType.forClass(data.getClass()); Optional> encoder = dataEncoders .stream() - .filter(e -> e.canEncode(elementType, MimeTypeUtils.APPLICATION_JSON)) + .filter(e -> e.canEncode(elementType, MimeTypeUtils.APPLICATION_JSON, Collections.emptyMap())) .findFirst(); return ((Encoder) 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)); } diff --git a/spring-web/src/main/java/org/springframework/web/client/reactive/ResponseExtractors.java b/spring-web/src/main/java/org/springframework/web/client/reactive/ResponseExtractors.java index f564cc1b9ba..1078c33f49c 100644 --- a/spring-web/src/main/java/org/springframework/web/client/reactive/ResponseExtractors.java +++ b/spring-web/src/main/java/org/springframework/web/client/reactive/ResponseExtractors.java @@ -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 { MediaType contentType = response.getHeaders().getContentType(); HttpMessageReader reader = resolveMessageReader(messageReaders, responseType, contentType); - return (Flux) reader.read(responseType, response); + return (Flux) reader.read(responseType, response, Collections.emptyMap()); } @SuppressWarnings("unchecked") @@ -188,14 +189,14 @@ public class ResponseExtractors { MediaType contentType = response.getHeaders().getContentType(); HttpMessageReader reader = resolveMessageReader(messageReaders, responseType, contentType); - return (Mono) reader.readMono(responseType, response); + return (Mono) reader.readMono(responseType, response, Collections.emptyMap()); } protected static HttpMessageReader resolveMessageReader(List> 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( diff --git a/spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java b/spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java index f7f1c675181..887c6c5cd3e 100644 --- a/spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java +++ b/spring-web/src/main/java/org/springframework/web/client/reactive/WebClient.java @@ -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> resolveWriter(List> 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(); } } diff --git a/spring-web/src/main/java/org/springframework/web/client/reactive/support/RxJava1ResponseExtractors.java b/spring-web/src/main/java/org/springframework/web/client/reactive/support/RxJava1ResponseExtractors.java index 0401384ceef..b6894aa071e 100644 --- a/spring-web/src/main/java/org/springframework/web/client/reactive/support/RxJava1ResponseExtractors.java +++ b/spring-web/src/main/java/org/springframework/web/client/reactive/support/RxJava1ResponseExtractors.java @@ -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 { MediaType contentType = response.getHeaders().getContentType(); HttpMessageReader converter = resolveMessageReader(messageReaders, responseType, contentType); - return (Flux) converter.read(responseType, response); + return (Flux) converter.read(responseType, response, Collections.emptyMap()); } @SuppressWarnings("unchecked") @@ -202,14 +203,14 @@ public class RxJava1ResponseExtractors { MediaType contentType = response.getHeaders().getContentType(); HttpMessageReader converter = resolveMessageReader(messageReaders, responseType, contentType); - return (Mono) converter.readMono(responseType, response); + return (Mono) converter.readMono(responseType, response, Collections.emptyMap()); } protected static HttpMessageReader resolveMessageReader(List> 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( diff --git a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java index cb04d626b70..b8ab039ad82 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/ServerSentEventHttpMessageWriterTests.java @@ -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 Mono> 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> result = outputMessage.getBodyWithFlush(); TestSubscriber.subscribe(result). @@ -89,7 +90,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll Flux 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> result = outputMessage.getBodyWithFlush(); TestSubscriber.subscribe(result). @@ -112,7 +113,7 @@ public class ServerSentEventHttpMessageWriterTests extends AbstractDataBufferAll Flux 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> result = outputMessage.getBodyWithFlush(); TestSubscriber.subscribe(result). @@ -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> result = outputMessage.getBodyWithFlush(); TestSubscriber.subscribe(result).