Browse Source

Merge refactoring steps in HTTP codec package

pull/1363/head
Rossen Stoyanchev 9 years ago
parent
commit
041437fd68
  1. 7
      spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java
  2. 107
      spring-web/src/main/java/org/springframework/http/codec/AbstractServerHttpMessageReader.java
  3. 93
      spring-web/src/main/java/org/springframework/http/codec/AbstractServerHttpMessageWriter.java
  4. 63
      spring-web/src/main/java/org/springframework/http/codec/DecoderHttpMessageReader.java
  5. 89
      spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java
  6. 10
      spring-web/src/main/java/org/springframework/http/codec/FormHttpMessageReader.java
  7. 12
      spring-web/src/main/java/org/springframework/http/codec/FormHttpMessageWriter.java
  8. 57
      spring-web/src/main/java/org/springframework/http/codec/HttpMessageReader.java
  9. 49
      spring-web/src/main/java/org/springframework/http/codec/HttpMessageWriter.java
  10. 65
      spring-web/src/main/java/org/springframework/http/codec/Jackson2ServerHttpMessageReader.java
  11. 103
      spring-web/src/main/java/org/springframework/http/codec/Jackson2ServerHttpMessageWriter.java
  12. 2
      spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java
  13. 50
      spring-web/src/main/java/org/springframework/http/codec/ServerHttpDecoder.java
  14. 52
      spring-web/src/main/java/org/springframework/http/codec/ServerHttpEncoder.java
  15. 47
      spring-web/src/main/java/org/springframework/http/codec/ServerHttpMessageReader.java
  16. 30
      spring-web/src/main/java/org/springframework/http/codec/ServerHttpMessageWriter.java
  17. 8
      spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java
  18. 31
      spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageWriter.java
  19. 31
      spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java
  20. 37
      spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java
  21. 12
      spring-webflux/src/main/java/org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.java
  22. 37
      spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java
  23. 12
      spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurer.java
  24. 12
      spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurerComposite.java
  25. 3
      spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultHandlerStrategiesBuilder.java
  26. 33
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageReaderArgumentResolver.java
  27. 24
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/AbstractMessageWriterResultHandler.java
  28. 6
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java
  29. 6
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java
  30. 8
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
  31. 8
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java
  32. 6
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java
  33. 8
      spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java
  34. 24
      spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java
  35. 6
      spring-webflux/src/test/java/org/springframework/web/reactive/function/client/ExchangeStrategiesTests.java
  36. 11
      spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DispatcherHandlerIntegrationTests.java
  37. 6
      spring-webflux/src/test/java/org/springframework/web/reactive/function/server/HandlerStrategiesTests.java
  38. 4
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java
  39. 6
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java
  40. 8
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java
  41. 4
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java
  42. 4
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java
  43. 6
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java

7
spring-core/src/main/java/org/springframework/core/codec/AbstractEncoder.java

@ -31,13 +31,6 @@ import org.springframework.util.MimeType; @@ -31,13 +31,6 @@ import org.springframework.util.MimeType;
*/
public abstract class AbstractEncoder<T> implements Encoder<T> {
/**
* Hint key to use with a {@link FlushingStrategy} value.
*/
public static final String FLUSHING_STRATEGY_HINT = AbstractEncoder.class.getName() + ".flushingStrategy";
public enum FlushingStrategy { AUTO, AFTER_EACH_ELEMENT }
private final List<MimeType> encodableMimeTypes;

107
spring-web/src/main/java/org/springframework/http/codec/AbstractServerHttpMessageReader.java

@ -1,107 +0,0 @@ @@ -1,107 +0,0 @@
/*
* 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.http.codec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
/**
* {@link HttpMessageReader} wrapper that implements {@link ServerHttpMessageReader} in order
* to allow providing hints to the nested {@code reader} or setting the response status for
* example, by implementing {@link #resolveReadHints(ResolvableType, ResolvableType, ServerHttpRequest)}.
*
* @author Sebastien Deleuze
* @since 5.0
*/
public abstract class AbstractServerHttpMessageReader<T> implements ServerHttpMessageReader<T> {
private HttpMessageReader<T> reader;
public AbstractServerHttpMessageReader(HttpMessageReader<T> reader) {
this.reader = reader;
}
@Override
public boolean canRead(ResolvableType elementType, MediaType mediaType) {
return this.reader.canRead(elementType, mediaType);
}
@Override
public Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) {
return this.reader.read(elementType, inputMessage, hints);
}
@Override
public Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) {
return this.reader.readMono(elementType, inputMessage, hints);
}
@Override
public List<MediaType> getReadableMediaTypes() {
return this.reader.getReadableMediaTypes();
}
@Override
public Flux<T> read(ResolvableType streamType, ResolvableType elementType,
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
Map<String, Object> mergedHints = new HashMap<>(hints);
mergedHints.putAll(resolveReadHints(streamType, elementType, request));
return (this.reader instanceof ServerHttpMessageReader ?
((ServerHttpMessageReader<T>)this.reader).read(streamType, elementType, request, response, mergedHints) :
this.read(elementType, request, mergedHints));
}
@Override
public Mono<T> readMono(ResolvableType streamType, ResolvableType elementType,
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
Map<String, Object> mergedHints = new HashMap<>(hints);
mergedHints.putAll(resolveReadHints(streamType, elementType, request));
return (this.reader instanceof ServerHttpMessageReader ?
((ServerHttpMessageReader<T>)this.reader).readMono(streamType, elementType, request, response, mergedHints) :
this.readMono(elementType, request, mergedHints));
}
/**
* Invoked before reading the request to resolve hints by
* {@link #read(ResolvableType, ResolvableType, ServerHttpRequest, ServerHttpResponse, Map)}.
*
* @param streamType the original type used for the method return value. For annotation
* based controllers, the {@link MethodParameter} is available via {@link ResolvableType#getSource()}.
* @param elementType the stream element type to process
* @param request the current HTTP request
* @return Additional information about how to write the body
*/
protected abstract Map<String, Object> resolveReadHints(ResolvableType streamType,
ResolvableType elementType, ServerHttpRequest request);
}

93
spring-web/src/main/java/org/springframework/http/codec/AbstractServerHttpMessageWriter.java

@ -1,93 +0,0 @@ @@ -1,93 +0,0 @@
/*
* 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.http.codec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
/**
* {@link HttpMessageWriter} wrapper that implements {@link ServerHttpMessageWriter} in order
* to allow providing hints to the nested {@code writer} or setting the response status for
* example, by implementing {@link #resolveWriteHints(ResolvableType, ResolvableType, MediaType, ServerHttpRequest)}.
*
* @author Sebastien Deleuze
* @since 5.0
*/
public abstract class AbstractServerHttpMessageWriter<T> implements ServerHttpMessageWriter<T> {
private HttpMessageWriter<T> writer;
public AbstractServerHttpMessageWriter(HttpMessageWriter<T> writer) {
this.writer = writer;
}
@Override
public boolean canWrite(ResolvableType elementType, MediaType mediaType) {
return this.writer.canWrite(elementType, mediaType);
}
@Override
public List<MediaType> getWritableMediaTypes() {
return this.writer.getWritableMediaTypes();
}
@Override
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType,
MediaType mediaType, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) {
return this.writer.write(inputStream, elementType, mediaType, outputMessage, hints);
}
@Override
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType streamType, ResolvableType elementType,
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
Map<String, Object> mergedHints = new HashMap<>(hints);
mergedHints.putAll(resolveWriteHints(streamType, elementType, mediaType, request));
return (this.writer instanceof ServerHttpMessageWriter ?
((ServerHttpMessageWriter<T>)this.writer).write(inputStream, streamType,
elementType, mediaType, request, response, mergedHints) :
this.writer.write(inputStream, elementType, mediaType, response, mergedHints));
}
/**
* Invoked before writing the response to resolve hints by
* {@link #write(Publisher, ResolvableType, ResolvableType, MediaType, ServerHttpRequest, ServerHttpResponse, Map)}.
* @param streamType the original type used for the method return value. For annotation
* based controllers, the {@link MethodParameter} is available via {@link ResolvableType#getSource()}.
* @param elementType the stream element type to process
* @param mediaType 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 request the current HTTP request
* @return additional information about how to write the body
*/
protected abstract Map<String, Object> resolveWriteHints(ResolvableType streamType, ResolvableType elementType,
MediaType mediaType, ServerHttpRequest request);
}

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

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.http.codec;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -28,17 +29,23 @@ import org.springframework.core.codec.Decoder; @@ -28,17 +29,23 @@ import org.springframework.core.codec.Decoder;
import org.springframework.http.HttpMessage;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpInputMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
/**
* Implementation of {@code HttpMessageReader} delegating to a {@link Decoder}.
* {@code HttpMessageReader} that wraps and delegates to a {@link Decoder}.
*
* <p>Also a {@code ServerHttpMessageReader} that pre-resolves decoding hints
* from the extra information available on the server side such as the request
* or controller method parameter annotations.
*
* @author Arjen Poutsma
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
* @since 5.0
*/
public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
public class DecoderHttpMessageReader<T> implements ServerHttpMessageReader<T> {
private final Decoder<T> decoder;
@ -74,19 +81,19 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> { @@ -74,19 +81,19 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
}
@Override
public Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage inputMessage,
public Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
MediaType contentType = getContentType(inputMessage);
return this.decoder.decode(inputMessage.getBody(), elementType, contentType, hints);
MediaType contentType = getContentType(message);
return this.decoder.decode(message.getBody(), elementType, contentType, hints);
}
@Override
public Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage inputMessage,
public Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
MediaType contentType = getContentType(inputMessage);
return this.decoder.decodeToMono(inputMessage.getBody(), elementType, contentType, hints);
MediaType contentType = getContentType(message);
return this.decoder.decodeToMono(message.getBody(), elementType, contentType, hints);
}
private MediaType getContentType(HttpMessage inputMessage) {
@ -94,4 +101,44 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> { @@ -94,4 +101,44 @@ public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
return (contentType != null ? contentType : MediaType.APPLICATION_OCTET_STREAM);
}
// ServerHttpMessageReader...
@Override
public Flux<T> read(ResolvableType actualType, ResolvableType elementType,
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
Map<String, Object> allHints = new HashMap<>(4);
allHints.putAll(getReadHints(actualType, elementType, request, response));
allHints.putAll(hints);
return read(elementType, request, allHints);
}
@Override
public Mono<T> readMono(ResolvableType actualType, ResolvableType elementType,
ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
Map<String, Object> allHints = new HashMap<>(4);
allHints.putAll(getReadHints(actualType, elementType, request, response));
allHints.putAll(hints);
return readMono(elementType, request, allHints);
}
/**
* Get additional hints for decoding for example based on the server request
* or annotations from controller method parameters. By default, delegate to
* the decoder if it is an instance of {@link ServerHttpDecoder}.
*/
protected Map<String, Object> getReadHints(ResolvableType streamType,
ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response) {
if (this.decoder instanceof ServerHttpDecoder) {
ServerHttpDecoder<?> httpDecoder = (ServerHttpDecoder<?>) this.decoder;
return httpDecoder.getDecodeHints(streamType, elementType, request, response);
}
return Collections.emptyMap();
}
}

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

@ -16,6 +16,9 @@ @@ -16,6 +16,9 @@
package org.springframework.http.codec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -29,20 +32,31 @@ import org.springframework.core.io.buffer.DataBuffer; @@ -29,20 +32,31 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import static org.springframework.core.codec.AbstractEncoder.FLUSHING_STRATEGY_HINT;
import static org.springframework.core.codec.AbstractEncoder.FlushingStrategy.AFTER_EACH_ELEMENT;
/**
* Implementation of {@code HttpMessageWriter} delegating to an {@link Encoder}.
* {@code HttpMessageWriter} that wraps and delegates to a {@link Encoder}.
*
* <p>Also a {@code ServerHttpMessageWriter} that pre-resolves encoding hints
* from the extra information available on the server side such as the request
* or controller method annotations.
*
* @author Arjen Poutsma
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
* @since 5.0
*/
public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
public class EncoderHttpMessageWriter<T> implements ServerHttpMessageWriter<T> {
/**
* Default list of media types that signify a "streaming" scenario such that
* there may be a time lag between items written and hence requires flushing.
*/
public static final List<MediaType> DEFAULT_STREAMING_MEDIA_TYPES =
Collections.singletonList(MediaType.APPLICATION_STREAM_JSON);
private final Encoder<T> encoder;
@ -50,6 +64,8 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -50,6 +64,8 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
private final MediaType defaultMediaType;
private final List<MediaType> streamingMediaTypes = new ArrayList<>(1);
/**
* Create an instance wrapping the given {@link Encoder}.
@ -59,6 +75,7 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -59,6 +75,7 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
this.encoder = encoder;
this.mediaTypes = MediaType.asMediaTypes(encoder.getEncodableMimeTypes());
this.defaultMediaType = initDefaultMediaType(this.mediaTypes);
this.streamingMediaTypes.addAll(DEFAULT_STREAMING_MEDIA_TYPES);
}
private static MediaType initDefaultMediaType(List<MediaType> mediaTypes) {
@ -78,6 +95,23 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -78,6 +95,23 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
return this.mediaTypes;
}
/**
* Configure "streaming" media types for which flushing should be performed
* automatically vs at the end of the input stream.
* <p>By default this is set to {@link #DEFAULT_STREAMING_MEDIA_TYPES}.
* @param mediaTypes one or more media types to add to the list
*/
public void setStreamingMediaTypes(List<MediaType> mediaTypes) {
this.streamingMediaTypes.addAll(mediaTypes);
}
/**
* Return the configured list of "streaming" media types.
*/
public List<MediaType> getStreamingMediaTypes() {
return Collections.unmodifiableList(this.streamingMediaTypes);
}
@Override
public boolean canWrite(ResolvableType elementType, MediaType mediaType) {
@ -86,10 +120,10 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -86,10 +120,10 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
@Override
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType,
MediaType mediaType, ReactiveHttpOutputMessage outputMessage,
MediaType mediaType, ReactiveHttpOutputMessage message,
Map<String, Object> hints) {
HttpHeaders headers = outputMessage.getHeaders();
HttpHeaders headers = message.getHeaders();
if (headers.getContentType() == null) {
MediaType fallback = this.defaultMediaType;
@ -101,10 +135,11 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -101,10 +135,11 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
}
Flux<DataBuffer> body = this.encoder.encode(inputStream,
outputMessage.bufferFactory(), elementType, headers.getContentType(), hints);
message.bufferFactory(), elementType, headers.getContentType(), hints);
return (hints.get(FLUSHING_STRATEGY_HINT) == AFTER_EACH_ELEMENT ?
outputMessage.writeAndFlushWith(body.map(Flux::just)) : outputMessage.writeWith(body));
return isStreamingMediaType(headers.getContentType()) ?
message.writeAndFlushWith(body.map(Flux::just)) :
message.writeWith(body);
}
private static boolean useFallback(MediaType main, MediaType fallback) {
@ -119,4 +154,38 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> { @@ -119,4 +154,38 @@ public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
return main;
}
private boolean isStreamingMediaType(MediaType contentType) {
return this.streamingMediaTypes.stream().anyMatch(contentType::isCompatibleWith);
}
// ServerHttpMessageWriter...
@Override
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType actualType,
ResolvableType elementType, MediaType mediaType, ServerHttpRequest request,
ServerHttpResponse response, Map<String, Object> hints) {
Map<String, Object> allHints = new HashMap<>();
allHints.putAll(getWriteHints(actualType, elementType, mediaType, request, response));
allHints.putAll(hints);
return write(inputStream, elementType, mediaType, response, allHints);
}
/**
* Get additional hints for encoding for example based on the server request
* or annotations from controller method parameters. By default, delegate to
* the encoder if it is an instance of {@link ServerHttpEncoder}.
*/
protected Map<String, Object> getWriteHints(ResolvableType streamType, ResolvableType elementType,
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
if (this.encoder instanceof ServerHttpEncoder) {
ServerHttpEncoder<?> httpEncoder = (ServerHttpEncoder<?>) this.encoder;
return httpEncoder.getEncodeHints(streamType, elementType, mediaType, request, response);
}
return Collections.emptyMap();
}
}

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

@ -83,19 +83,19 @@ public class FormHttpMessageReader implements HttpMessageReader<MultiValueMap<St @@ -83,19 +83,19 @@ public class FormHttpMessageReader implements HttpMessageReader<MultiValueMap<St
@Override
public Flux<MultiValueMap<String, String>> read(ResolvableType elementType,
ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) {
ReactiveHttpInputMessage message, Map<String, Object> hints) {
return Flux.from(readMono(elementType, inputMessage, hints));
return Flux.from(readMono(elementType, message, hints));
}
@Override
public Mono<MultiValueMap<String, String>> readMono(ResolvableType elementType,
ReactiveHttpInputMessage inputMessage, Map<String, Object> hints) {
ReactiveHttpInputMessage message, Map<String, Object> hints) {
MediaType contentType = inputMessage.getHeaders().getContentType();
MediaType contentType = message.getHeaders().getContentType();
Charset charset = getMediaTypeCharset(contentType);
return inputMessage.getBody()
return message.getBody()
.reduce(DataBuffer::write)
.map(buffer -> {
CharBuffer charBuffer = charset.decode(buffer.asByteBuffer());

12
spring-web/src/main/java/org/springframework/http/codec/FormHttpMessageWriter.java

@ -82,13 +82,13 @@ public class FormHttpMessageWriter implements HttpMessageWriter<MultiValueMap<St @@ -82,13 +82,13 @@ public class FormHttpMessageWriter implements HttpMessageWriter<MultiValueMap<St
@Override
public Mono<Void> write(Publisher<? extends MultiValueMap<String, String>> inputStream,
ResolvableType elementType, MediaType mediaType, ReactiveHttpOutputMessage outputMessage,
ResolvableType elementType, MediaType mediaType, ReactiveHttpOutputMessage message,
Map<String, Object> hints) {
MediaType contentType = outputMessage.getHeaders().getContentType();
MediaType contentType = message.getHeaders().getContentType();
if (contentType == null) {
contentType = MediaType.APPLICATION_FORM_URLENCODED;
outputMessage.getHeaders().setContentType(contentType);
message.getHeaders().setContentType(contentType);
}
Charset charset = getMediaTypeCharset(contentType);
@ -99,9 +99,9 @@ public class FormHttpMessageWriter implements HttpMessageWriter<MultiValueMap<St @@ -99,9 +99,9 @@ public class FormHttpMessageWriter implements HttpMessageWriter<MultiValueMap<St
.map(form -> generateForm(form, charset))
.then(value -> {
ByteBuffer byteBuffer = charset.encode(value);
DataBuffer buffer = outputMessage.bufferFactory().wrap(byteBuffer);
outputMessage.getHeaders().setContentLength(byteBuffer.remaining());
return outputMessage.writeWith(Mono.just(buffer));
DataBuffer buffer = message.bufferFactory().wrap(byteBuffer);
message.getHeaders().setContentLength(byteBuffer.remaining());
return message.writeWith(Mono.just(buffer));
});
}

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

@ -1,5 +1,5 @@ @@ -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.
@ -27,8 +27,10 @@ import org.springframework.http.MediaType; @@ -27,8 +27,10 @@ import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpInputMessage;
/**
* Strategy interface that specifies a reader that can convert from the HTTP
* request body from a stream of bytes to Objects.
* Strategy for reading from a {@link ReactiveHttpInputMessage} and decoding
* the stream of bytes to Objects of type {@code <T>}.
*
* @param <T> the type of objects in the decoded output stream
*
* @author Rossen Stoyanchev
* @author Arjen Poutsma
@ -38,40 +40,39 @@ import org.springframework.http.ReactiveHttpInputMessage; @@ -38,40 +40,39 @@ import org.springframework.http.ReactiveHttpInputMessage;
public interface HttpMessageReader<T> {
/**
* Indicates whether the given class can be read by this converter.
* @param elementType the stream element 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.
* @return {@code true} if readable; {@code false} otherwise
* Return the {@link MediaType}'s that this reader supports.
*/
boolean canRead(ResolvableType elementType, MediaType mediaType);
List<MediaType> getReadableMediaTypes();
/**
* Read a {@link Flux} of the given type form the given input message, and returns it.
* @param elementType the stream element type to return. This type must have previously been
* 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 read the body
* @return the converted {@link Flux} of elements
* Whether the given object type is supported by this reader.
* @param elementType the type of object to check
* @param mediaType the media type for the read, possibly {@code null}
* @return {@code true} if readable, {@code false} otherwise
*/
Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints);
boolean canRead(ResolvableType elementType, MediaType mediaType);
/**
* Read a {@link Mono} of the given type form the given input message, and returns it.
* @param elementType the stream element type to return. This type must have previously been
* 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 read the body
* @return the converted {@link Mono} of object
* Read from the input message and encode to a stream of objects.
*
* @param elementType the type of objects in the stream which must have been
* previously checked via {@link #canRead(ResolvableType, MediaType)}
* @param message the message to read from
* @param hints additional information about how to read and decode the input
* @return the decoded stream of elements
*/
Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints);
Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage message, 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
* Read from the input message and encode to a single object.
*
* @param elementType the type of objects in the stream which must have been
* previously checked via {@link #canRead(ResolvableType, MediaType)}
* @param message the message to read from
* @param hints additional information about how to read and decode the input
* @return the decoded object
*/
List<MediaType> getReadableMediaTypes();
Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints);
}

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

@ -1,5 +1,5 @@ @@ -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.
@ -27,8 +27,10 @@ import org.springframework.http.MediaType; @@ -27,8 +27,10 @@ import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
/**
* Strategy interface that specifies a converter that can convert a stream of
* Objects to a stream of bytes to be written to the HTTP response body.
* Strategy for encoding a stream of objects of type {@code <T>} and writing
* the encoded stream of bytes to an {@link ReactiveHttpOutputMessage}.
*
* @param <T> the type of objects in the input stream
*
* @author Rossen Stoyanchev
* @author Arjen Poutsma
@ -38,34 +40,31 @@ import org.springframework.http.ReactiveHttpOutputMessage; @@ -38,34 +40,31 @@ import org.springframework.http.ReactiveHttpOutputMessage;
public interface HttpMessageWriter<T> {
/**
* Indicates whether the given class can be written by this converter.
* @param elementType the stream element type 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.
* @return {@code true} if writable; {@code false} otherwise
* Return the {@link MediaType}'s that this writer supports.
*/
boolean canWrite(ResolvableType elementType, MediaType mediaType);
List<MediaType> getWritableMediaTypes();
/**
* Write an given object to the given output message.
* @param inputStream the input stream to write
* @param elementType the stream element type to process. This type must have previously
* been passed to the {@link #canWrite} canWrite} method of this interface, which must
* have returned {@code true}.
* @param mediaType the content type to use when writing, typically the value of an
* {@code Accept} header. 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 write
* @return a {@link Mono} that indicates completion or error
* Whether the given object type is supported by this writer.
* @param elementType the type of object to check
* @param mediaType the media type for the write, possibly {@code null}
* @return {@code true} if writable, {@code false} otherwise
*/
Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType,
MediaType mediaType, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints);
boolean canWrite(ResolvableType elementType, MediaType mediaType);
/**
* Return the list of {@link MediaType} objects that can be written by this converter.
* @return the list of supported readable media types
* Write an given stream of object to the output message.
* @param inputStream the objects to write
* @param elementType the type of objects in the stream which must have been
* previously checked via {@link #canWrite(ResolvableType, MediaType)}
* @param mediaType the content type for the write, possibly {@code null} to
* indicate that the default content type of the writer must be used.
* @param message the message to write to
* @param hints additional information about how to encode and write
* @return indicates completion or error
*/
List<MediaType> getWritableMediaTypes();
Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType,
MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints);
}

65
spring-web/src/main/java/org/springframework/http/codec/Jackson2ServerHttpMessageReader.java

@ -1,65 +0,0 @@ @@ -1,65 +0,0 @@
/*
* 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.http.codec;
import java.util.Collections;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonView;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.http.codec.json.AbstractJackson2Codec;
import org.springframework.http.server.reactive.ServerHttpRequest;
/**
* {@link ServerHttpMessageReader} that resolves those annotation or request based Jackson 2 hints:
* <ul>
* <li>{@code @JsonView} + {@code @RequestBody} annotated handler method parameter</li>
* </ul>
*
* @author Sebastien Deleuze
* @since 5.0
* @see com.fasterxml.jackson.annotation.JsonView
*/
public class Jackson2ServerHttpMessageReader extends AbstractServerHttpMessageReader<Object> {
public Jackson2ServerHttpMessageReader(HttpMessageReader<Object> reader) {
super(reader);
}
@Override
protected Map<String, Object> resolveReadHints(ResolvableType streamType,
ResolvableType elementType, ServerHttpRequest request) {
Object source = streamType.getSource();
MethodParameter parameter = (source instanceof MethodParameter ? (MethodParameter)source : null);
if (parameter != null) {
JsonView annotation = parameter.getParameterAnnotation(JsonView.class);
if (annotation != null) {
Class<?>[] classes = annotation.value();
if (classes.length != 1) {
throw new IllegalArgumentException(
"@JsonView only supported for read hints with exactly 1 class argument: " + parameter);
}
return Collections.singletonMap(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
}
}
return Collections.emptyMap();
}
}

103
spring-web/src/main/java/org/springframework/http/codec/Jackson2ServerHttpMessageWriter.java

@ -1,103 +0,0 @@ @@ -1,103 +0,0 @@
/*
* 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.http.codec;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonView;
import org.reactivestreams.Publisher;
import static org.springframework.core.codec.AbstractEncoder.FLUSHING_STRATEGY_HINT;
import static org.springframework.core.codec.AbstractEncoder.FlushingStrategy.AFTER_EACH_ELEMENT;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.AbstractEncoder;
import org.springframework.core.codec.Encoder;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.json.AbstractJackson2Codec;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
/**
* Jackson {@link ServerHttpMessageWriter} that resolves {@code @JsonView} annotated handler
* method and deals with {@link AbstractEncoder#FLUSHING_STRATEGY_HINT}.
*
* @author Sebastien Deleuze
* @since 5.0
* @see com.fasterxml.jackson.annotation.JsonView
*/
public class Jackson2ServerHttpMessageWriter extends AbstractServerHttpMessageWriter<Object> {
public Jackson2ServerHttpMessageWriter(Encoder<Object> encoder) {
super(new EncoderHttpMessageWriter<>(encoder));
}
public Jackson2ServerHttpMessageWriter(HttpMessageWriter<Object> writer) {
super(writer);
}
@Override
protected Map<String, Object> resolveWriteHints(ResolvableType streamType,
ResolvableType elementType, MediaType mediaType, ServerHttpRequest request) {
Map<String, Object> hints = new HashMap<>();
Object source = streamType.getSource();
MethodParameter returnValue = (source instanceof MethodParameter ? (MethodParameter)source : null);
if (returnValue != null) {
JsonView annotation = returnValue.getMethodAnnotation(JsonView.class);
if (annotation != null) {
Class<?>[] classes = annotation.value();
if (classes.length != 1) {
throw new IllegalArgumentException(
"@JsonView only supported for write hints with exactly 1 class argument: " + returnValue);
}
hints.put(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
}
}
return hints;
}
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType elementType, MediaType mediaType,
ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) {
if ((mediaType != null) && mediaType.isCompatibleWith(MediaType.APPLICATION_STREAM_JSON)) {
Map<String, Object> hintsWithFlush = new HashMap<>(hints);
hintsWithFlush.put(FLUSHING_STRATEGY_HINT, AFTER_EACH_ELEMENT);
return super.write(inputStream, elementType, mediaType, outputMessage, hintsWithFlush);
}
return super.write(inputStream, elementType, mediaType, outputMessage, hints);
}
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType streamType, ResolvableType elementType,
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response, Map<String, Object> hints) {
if ((mediaType != null) && mediaType.isCompatibleWith(MediaType.APPLICATION_STREAM_JSON)) {
Map<String, Object> hintsWithFlush = new HashMap<>(hints);
hintsWithFlush.put(FLUSHING_STRATEGY_HINT, AFTER_EACH_ELEMENT);
return super.write(inputStream, streamType, elementType, mediaType, request, response, hintsWithFlush);
}
return super.write(inputStream, streamType, elementType, mediaType, request, response, hints);
}
}

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

@ -176,7 +176,7 @@ public class ResourceHttpMessageWriter implements ServerHttpMessageWriter<Resour @@ -176,7 +176,7 @@ public class ResourceHttpMessageWriter implements ServerHttpMessageWriter<Resour
@Override
@SuppressWarnings("unchecked")
public Mono<Void> write(Publisher<? extends Resource> inputStream, ResolvableType streamType,
public Mono<Void> write(Publisher<? extends Resource> inputStream, ResolvableType actualType,
ResolvableType elementType, MediaType mediaType, ServerHttpRequest request,
ServerHttpResponse response, Map<String, Object> hints) {

50
spring-web/src/main/java/org/springframework/http/codec/ServerHttpDecoder.java

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
/*
* 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.
* 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.http.codec;
import java.util.Map;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Decoder;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
/**
* {@code Decoder} extension for server-side decoding of the HTTP request body.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public interface ServerHttpDecoder<T> extends Decoder<T> {
/**
* Get decoding hints based on the server request or annotations on the
* target controller method parameter.
*
* @param actualType the actual target type to decode to, possibly a reactive
* wrapper and sourced from {@link org.springframework.core.MethodParameter},
* i.e. providing access to method parameter annotations.
* @param elementType the element type within {@code Flux/Mono} that we're
* trying to decode to.
* @param request the current request
* @param response the current response
* @return a Map with hints, possibly empty
*/
Map<String, Object> getDecodeHints(ResolvableType actualType, ResolvableType elementType,
ServerHttpRequest request, ServerHttpResponse response);
}

52
spring-web/src/main/java/org/springframework/http/codec/ServerHttpEncoder.java

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
/*
* 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.
* 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.http.codec;
import java.util.Map;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Encoder;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
/**
* {@code Encoder} extension for server-side encoding of the HTTP response body.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public interface ServerHttpEncoder<T> extends Encoder<T> {
/**
* Get decoding hints based on the server request or annotations on the
* target controller method parameter.
*
* @param actualType the actual source type to encode, possibly a reactive
* wrapper and sourced from {@link org.springframework.core.MethodParameter},
* i.e. providing access to method annotations.
* @param elementType the element type within {@code Flux/Mono} that we're
* trying to encode.
* @param request the current request
* @param response the current response
* @return a Map with hints, possibly empty
*/
Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response);
}

47
spring-web/src/main/java/org/springframework/http/codec/ServerHttpMessageReader.java

@ -1,5 +1,5 @@ @@ -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.
@ -27,46 +27,43 @@ import org.springframework.http.server.reactive.ServerHttpRequest; @@ -27,46 +27,43 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
/**
* Server oriented {@link HttpMessageReader} that allows to resolve hints using annotations or
* perform additional operation using {@link ServerHttpRequest} or {@link ServerHttpResponse}.
* An extension of {@code HttpMessageReader} for decoding and reading the
* request body with extra information available on the server side.
*
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
* @since 5.0
*/
public interface ServerHttpMessageReader<T> extends HttpMessageReader<T> {
/**
* Read a {@link Flux} of the given type form the given input message with additional server related
* parameters which could be used to create some hints or set the response status for example.
* Decode and read the request body to an object stream.
*
* Return hints that can be used to customize how the body should be read
* @param streamType the original type used in the method parameter. For annotation
* based controllers, the {@link MethodParameter} is available via {@link ResolvableType#getSource()}.
* @param elementType the stream element type to return
* Typically the value of a {@code Content-Type} header.
* @param request the current HTTP request
* @param response the current HTTP response
* @param actualType the actual type of the target method parameter; for
* annotated controllers, the {@link MethodParameter} can be accessed via
* {@link ResolvableType#getSource()}.
* @param elementType the type of Objects in the output stream
* @param request the current request
* @param response the current response
* @param hints additional information about how to read the body
* @return the converted {@link Flux} of elements
* @return the decoded stream of elements
*/
Flux<T> read(ResolvableType streamType, ResolvableType elementType, ServerHttpRequest request,
Flux<T> read(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request,
ServerHttpResponse response, Map<String, Object> hints);
/**
* Read a {@link Mono} of the given type form the given input message with additional server related
* parameters which could be used to create some hints or set the response status for example.
* Decode and read the request body to a single object.
*
* Return hints that can be used to customize how the body should be read
* @param streamType the original type used in the method parameter. For annotation
* based controllers, the {@link MethodParameter} is available via {@link ResolvableType#getSource()}.
* @param elementType the stream element type to return
* Typically the value of a {@code Content-Type} header.
* @param request the current HTTP request
* @param response the current HTTP response
* @param actualType the actual type of the target method parameter; for
* annotated controllers, the {@link MethodParameter} can be accessed via
* {@link ResolvableType#getSource()}.
* @param elementType the type of Objects in the output stream
* @param request the current request
* @param response the current response
* @param hints additional information about how to read the body
* @return the converted {@link Mono} of object
* @return the decoded stream of elements
*/
Mono<T> readMono(ResolvableType streamType, ResolvableType elementType, ServerHttpRequest request,
Mono<T> readMono(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request,
ServerHttpResponse response, Map<String, Object> hints);
}

30
spring-web/src/main/java/org/springframework/http/codec/ServerHttpMessageWriter.java

@ -1,5 +1,5 @@ @@ -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.
@ -28,29 +28,29 @@ import org.springframework.http.server.reactive.ServerHttpRequest; @@ -28,29 +28,29 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
/**
* Server oriented {@link HttpMessageWriter} that allows to resolve hints using annotations or
* perform additional operation using {@link ServerHttpRequest} or {@link ServerHttpResponse}.
* An extension of {@code HttpMessageWriter} for encoding and writing the
* response body with extra information available on the server side.
*
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
* @since 5.0
*/
public interface ServerHttpMessageWriter<T> extends HttpMessageWriter<T> {
/**
* Write a given object to the given output message with additional server related
* parameters which could be used to create some hints or set the response status for example.
* Encode and write the given object stream to the response.
*
* @param streamType the original type used for the method return value. For annotation
* based controllers, the {@link MethodParameter} is available via {@link ResolvableType#getSource()}.
* Can be {@code null}.
* @param elementType the stream element type to process
* @param mediaType 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 request the current HTTP request
* @param response the current HTTP response
* @return a {@link Mono} that indicates completion or error
* @param actualType the actual return type of the method that returned the
* value; for annotated controllers, the {@link MethodParameter} can be
* accessed via {@link ResolvableType#getSource()}.
* @param elementType the type of Objects in the input stream
* @param mediaType the content type to use, possibly {@code null} indicating
* the default content type of the writer should be used.
* @param request the current request
* @param response the current response
* @return a {@link Mono} that indicates completion of writing or error
*/
Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType streamType,
Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType actualType,
ResolvableType elementType, MediaType mediaType, ServerHttpRequest request,
ServerHttpResponse response, Map<String, Object> hints);

8
spring-web/src/main/java/org/springframework/http/codec/ServerSentEventHttpMessageReader.java

@ -87,13 +87,13 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec @@ -87,13 +87,13 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
@Override
public Flux<Object> read(ResolvableType elementType, ReactiveHttpInputMessage inputMessage,
public Flux<Object> read(ResolvableType elementType, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
boolean hasSseWrapper = ServerSentEvent.class.isAssignableFrom(elementType.getRawClass());
ResolvableType dataType = (hasSseWrapper ? elementType.getGeneric(0) : elementType);
return Flux.from(inputMessage.getBody())
return Flux.from(message.getBody())
.concatMap(ServerSentEventHttpMessageReader::splitOnNewline)
.map(buffer -> {
CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
@ -178,13 +178,13 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec @@ -178,13 +178,13 @@ public class ServerSentEventHttpMessageReader implements HttpMessageReader<Objec
}
@Override
public Mono<Object> readMono(ResolvableType elementType, ReactiveHttpInputMessage inputMessage,
public Mono<Object> readMono(ResolvableType elementType, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
// Let's give StringDecoder a chance since SSE is ordered ahead of it
if (String.class.equals(elementType.getRawClass())) {
Flux<DataBuffer> body = inputMessage.getBody();
Flux<DataBuffer> body = message.getBody();
return stringDecoder.decodeToMono(body, elementType, null, null).cast(Object.class);
}

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

@ -35,6 +35,8 @@ import org.springframework.core.io.buffer.DataBuffer; @@ -35,6 +35,8 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.MimeTypeUtils;
@ -47,7 +49,7 @@ import org.springframework.util.MimeTypeUtils; @@ -47,7 +49,7 @@ import org.springframework.util.MimeTypeUtils;
* @author Arjen Poutsma
* @since 5.0
*/
public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Object> {
public class ServerSentEventHttpMessageWriter implements ServerHttpMessageWriter<Object> {
/**
* Server-Sent Events hint key expecting a {@link Boolean} value which when set to true
@ -85,14 +87,14 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec @@ -85,14 +87,14 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType elementType, MediaType mediaType,
ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints) {
ReactiveHttpOutputMessage message, Map<String, Object> hints) {
outputMessage.getHeaders().setContentType(MediaType.TEXT_EVENT_STREAM);
message.getHeaders().setContentType(MediaType.TEXT_EVENT_STREAM);
DataBufferFactory bufferFactory = outputMessage.bufferFactory();
DataBufferFactory bufferFactory = message.bufferFactory();
Flux<Publisher<DataBuffer>> body = encode(inputStream, bufferFactory, elementType, hints);
return outputMessage.writeAndFlushWith(body);
return message.writeAndFlushWith(body);
}
private Flux<Publisher<DataBuffer>> encode(Publisher<?> inputStream, DataBufferFactory bufferFactory,
@ -161,4 +163,23 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec @@ -161,4 +163,23 @@ public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Objec
return Mono.just(buffer);
}
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType actualType, ResolvableType elementType,
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response,
Map<String, Object> hints) {
Map<String, Object> allHints = this.dataEncoders.stream()
.filter(encoder -> encoder instanceof ServerHttpEncoder)
.map(encoder -> (ServerHttpEncoder<?>) encoder)
.map(encoder -> encoder.getEncodeHints(actualType, elementType, mediaType, request, response))
.reduce(new HashMap<>(), (t, u) -> {
t.putAll(u);
return t;
});
allHints.putAll(hints);
return write(inputStream, elementType, mediaType, response, allHints);
}
}

31
spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonDecoder.java

@ -17,9 +17,11 @@ @@ -17,9 +17,11 @@
package org.springframework.http.codec.json;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
@ -30,10 +32,12 @@ import reactor.core.publisher.Mono; @@ -30,10 +32,12 @@ import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.CodecException;
import org.springframework.core.codec.Decoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.codec.ServerHttpDecoder;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
@ -45,7 +49,7 @@ import org.springframework.util.MimeType; @@ -45,7 +49,7 @@ import org.springframework.util.MimeType;
* @since 5.0
* @see Jackson2JsonEncoder
*/
public class Jackson2JsonDecoder extends AbstractJackson2Codec implements Decoder<Object> {
public class Jackson2JsonDecoder extends AbstractJackson2Codec implements ServerHttpDecoder<Object> {
private final JsonObjectDecoder fluxObjectDecoder = new JsonObjectDecoder(true);
@ -123,4 +127,27 @@ public class Jackson2JsonDecoder extends AbstractJackson2Codec implements Decode @@ -123,4 +127,27 @@ public class Jackson2JsonDecoder extends AbstractJackson2Codec implements Decode
});
}
// ServerHttpDecoder...
@Override
public Map<String, Object> getDecodeHints(ResolvableType actualType, ResolvableType elementType,
ServerHttpRequest request, ServerHttpResponse response) {
Object source = actualType.getSource();
MethodParameter parameter = (source instanceof MethodParameter ? (MethodParameter)source : null);
if (parameter != null) {
JsonView annotation = parameter.getParameterAnnotation(JsonView.class);
if (annotation != null) {
Class<?>[] classes = annotation.value();
if (classes.length != 1) {
throw new IllegalArgumentException(
"@JsonView only supported for read hints with exactly 1 class argument: " + parameter);
}
return Collections.singletonMap(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
}
}
return Collections.emptyMap();
}
}

37
spring-web/src/main/java/org/springframework/http/codec/json/Jackson2JsonEncoder.java

@ -18,9 +18,11 @@ package org.springframework.http.codec.json; @@ -18,9 +18,11 @@ package org.springframework.http.codec.json;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonView;
import com.fasterxml.jackson.core.PrettyPrinter;
import com.fasterxml.jackson.core.util.DefaultIndenter;
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
@ -31,20 +33,25 @@ import com.fasterxml.jackson.databind.SerializationConfig; @@ -31,20 +33,25 @@ import com.fasterxml.jackson.databind.SerializationConfig;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.reactivestreams.Publisher;
import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ResolvableType;
import org.springframework.core.codec.CodecException;
import org.springframework.core.codec.Encoder;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerHttpEncoder;
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.MimeType;
import static org.springframework.http.MediaType.APPLICATION_STREAM_JSON;
/**
* Encode from an {@code Object} stream to a byte stream of JSON objects,
* using Jackson 2.6+.
@ -54,7 +61,7 @@ import org.springframework.util.MimeType; @@ -54,7 +61,7 @@ import org.springframework.util.MimeType;
* @since 5.0
* @see Jackson2JsonDecoder
*/
public class Jackson2JsonEncoder extends AbstractJackson2Codec implements Encoder<Object> {
public class Jackson2JsonEncoder extends AbstractJackson2Codec implements ServerHttpEncoder<Object> {
private final PrettyPrinter ssePrettyPrinter;
@ -144,4 +151,28 @@ public class Jackson2JsonEncoder extends AbstractJackson2Codec implements Encode @@ -144,4 +151,28 @@ public class Jackson2JsonEncoder extends AbstractJackson2Codec implements Encode
return buffer;
}
// ServerHttpEncoder...
@Override
public Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
Map<String, Object> hints = new HashMap<>();
Object source = actualType.getSource();
MethodParameter returnValue = (source instanceof MethodParameter ? (MethodParameter)source : null);
if (returnValue != null) {
JsonView annotation = returnValue.getMethodAnnotation(JsonView.class);
if (annotation != null) {
Class<?>[] classes = annotation.value();
if (classes.length != 1) {
throw new IllegalArgumentException(
"@JsonView only supported for write hints with exactly 1 class argument: " + returnValue);
}
hints.put(AbstractJackson2Codec.JSON_VIEW_HINT, classes[0]);
}
}
return hints;
}
}

12
spring-webflux/src/main/java/org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.java

@ -21,8 +21,8 @@ import java.util.List; @@ -21,8 +21,8 @@ import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
@ -76,12 +76,12 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport @@ -76,12 +76,12 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport
}
@Override
protected void configureMessageReaders(List<HttpMessageReader<?>> messageReaders) {
protected void configureMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
this.configurers.configureMessageReaders(messageReaders);
}
@Override
protected void extendMessageReaders(List<HttpMessageReader<?>> messageReaders) {
protected void extendMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
this.configurers.extendMessageReaders(messageReaders);
}
@ -101,12 +101,12 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport @@ -101,12 +101,12 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport
}
@Override
protected void configureMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
protected void configureMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
this.configurers.configureMessageWriters(messageWriters);
}
@Override
protected void extendMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
protected void extendMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
this.configurers.extendMessageWriters(messageWriters);
}

37
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java

@ -48,11 +48,9 @@ import org.springframework.format.support.FormattingConversionService; @@ -48,11 +48,9 @@ import org.springframework.format.support.FormattingConversionService;
import org.springframework.http.MediaType;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.Jackson2ServerHttpMessageReader;
import org.springframework.http.codec.Jackson2ServerHttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
@ -106,9 +104,9 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -106,9 +104,9 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
private PathMatchConfigurer pathMatchConfigurer;
private List<HttpMessageReader<?>> messageReaders;
private List<ServerHttpMessageReader<?>> messageReaders;
private List<HttpMessageWriter<?>> messageWriters;
private List<ServerHttpMessageWriter<?>> messageWriters;
private ApplicationContext applicationContext;
@ -301,7 +299,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -301,7 +299,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
* <p>Use {@link #configureMessageReaders} to configure the list or
* {@link #extendMessageReaders} to add in addition to the default ones.
*/
protected final List<HttpMessageReader<?>> getMessageReaders() {
protected final List<ServerHttpMessageReader<?>> getMessageReaders() {
if (this.messageReaders == null) {
this.messageReaders = new ArrayList<>();
configureMessageReaders(this.messageReaders);
@ -320,7 +318,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -320,7 +318,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
* {@link #addDefaultHttpMessageReaders}.
* @param messageReaders a list to add message readers to, initially an empty
*/
protected void configureMessageReaders(List<HttpMessageReader<?>> messageReaders) {
protected void configureMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
}
/**
@ -329,7 +327,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -329,7 +327,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
* {@code ByteBuffer}, {@code String}, {@code Resource}, JAXB2, and Jackson
* (if present on the classpath).
*/
protected final void addDefaultHttpMessageReaders(List<HttpMessageReader<?>> readers) {
protected final void addDefaultHttpMessageReaders(List<ServerHttpMessageReader<?>> readers) {
readers.add(new DecoderHttpMessageReader<>(new ByteArrayDecoder()));
readers.add(new DecoderHttpMessageReader<>(new ByteBufferDecoder()));
readers.add(new DecoderHttpMessageReader<>(new DataBufferDecoder()));
@ -339,8 +337,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -339,8 +337,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
readers.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder()));
}
if (jackson2Present) {
readers.add(new Jackson2ServerHttpMessageReader(
new DecoderHttpMessageReader<>(new Jackson2JsonDecoder())));
readers.add(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
}
}
@ -348,7 +345,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -348,7 +345,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
* Override this to modify the list of message readers after it has been
* configured, for example to add some in addition to the default ones.
*/
protected void extendMessageReaders(List<HttpMessageReader<?>> messageReaders) {
protected void extendMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
}
/**
@ -453,7 +450,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -453,7 +450,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
* <p>Use {@link #configureMessageWriters(List)} to configure the list or
* {@link #extendMessageWriters(List)} to add in addition to the default ones.
*/
protected final List<HttpMessageWriter<?>> getMessageWriters() {
protected final List<ServerHttpMessageWriter<?>> getMessageWriters() {
if (this.messageWriters == null) {
this.messageWriters = new ArrayList<>();
configureMessageWriters(this.messageWriters);
@ -471,13 +468,13 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -471,13 +468,13 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
* {@link #addDefaultHttpMessageWriters}.
* @param messageWriters a list to add message writers to, initially an empty
*/
protected void configureMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
protected void configureMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
}
/**
* Adds default converters that sub-classes can call from
* {@link #configureMessageWriters(List)}.
*/
protected final void addDefaultHttpMessageWriters(List<HttpMessageWriter<?>> writers) {
protected final void addDefaultHttpMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
List<Encoder<?>> sseDataEncoders = new ArrayList<>();
writers.add(new EncoderHttpMessageWriter<>(new ByteArrayEncoder()));
writers.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
@ -489,21 +486,17 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @@ -489,21 +486,17 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
}
if (jackson2Present) {
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
writers.add(new Jackson2ServerHttpMessageWriter(encoder));
writers.add(new EncoderHttpMessageWriter<>(encoder));
sseDataEncoders.add(encoder);
HttpMessageWriter<Object> writer = new ServerSentEventHttpMessageWriter(sseDataEncoders);
writers.add(new Jackson2ServerHttpMessageWriter(writer));
}
else {
writers.add(new ServerSentEventHttpMessageWriter(sseDataEncoders));
}
writers.add(new ServerSentEventHttpMessageWriter(sseDataEncoders));
}
/**
* Override this to modify the list of message writers after it has been
* configured, for example to add some in addition to the default ones.
*/
protected void extendMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
protected void extendMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
}
@Bean

12
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurer.java

@ -22,8 +22,8 @@ import java.util.Optional; @@ -22,8 +22,8 @@ import java.util.Optional;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
@ -97,14 +97,14 @@ public interface WebFluxConfigurer { @@ -97,14 +97,14 @@ public interface WebFluxConfigurer {
* in addition to the default ones.
* @param readers an empty list to add message readers to
*/
default void configureMessageReaders(List<HttpMessageReader<?>> readers) {
default void configureMessageReaders(List<ServerHttpMessageReader<?>> readers) {
}
/**
* An alternative to {@link #configureMessageReaders(List)} that allows
* modifying the message readers to use after default ones have been added.
*/
default void extendMessageReaders(List<HttpMessageReader<?>> readers) {
default void extendMessageReaders(List<ServerHttpMessageReader<?>> readers) {
}
/**
@ -141,14 +141,14 @@ public interface WebFluxConfigurer { @@ -141,14 +141,14 @@ public interface WebFluxConfigurer {
* in addition to the default ones.
* @param writers a empty list to add message writers to
*/
default void configureMessageWriters(List<HttpMessageWriter<?>> writers) {
default void configureMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
}
/**
* An alternative to {@link #configureMessageWriters(List)} that allows
* modifying the message writers to use after default ones have been added.
*/
default void extendMessageWriters(List<HttpMessageWriter<?>> writers) {
default void extendMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
}
/**

12
spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurerComposite.java

@ -23,8 +23,8 @@ import java.util.function.Function; @@ -23,8 +23,8 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
@ -76,12 +76,12 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer { @@ -76,12 +76,12 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
}
@Override
public void configureMessageReaders(List<HttpMessageReader<?>> readers) {
public void configureMessageReaders(List<ServerHttpMessageReader<?>> readers) {
this.delegates.stream().forEach(delegate -> delegate.configureMessageReaders(readers));
}
@Override
public void extendMessageReaders(List<HttpMessageReader<?>> readers) {
public void extendMessageReaders(List<ServerHttpMessageReader<?>> readers) {
this.delegates.stream().forEach(delegate -> delegate.extendMessageReaders(readers));
}
@ -101,12 +101,12 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer { @@ -101,12 +101,12 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
}
@Override
public void configureMessageWriters(List<HttpMessageWriter<?>> writers) {
public void configureMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
this.delegates.stream().forEach(delegate -> delegate.configureMessageWriters(writers));
}
@Override
public void extendMessageWriters(List<HttpMessageWriter<?>> writers) {
public void extendMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
this.delegates.stream().forEach(delegate -> delegate.extendMessageWriters(writers));
}

3
spring-webflux/src/main/java/org/springframework/web/reactive/function/server/DefaultHandlerStrategiesBuilder.java

@ -37,7 +37,6 @@ import org.springframework.http.codec.EncoderHttpMessageWriter; @@ -37,7 +37,6 @@ import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.FormHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.Jackson2ServerHttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
@ -99,7 +98,7 @@ class DefaultHandlerStrategiesBuilder implements HandlerStrategies.Builder { @@ -99,7 +98,7 @@ class DefaultHandlerStrategiesBuilder implements HandlerStrategies.Builder {
if (jackson2Present) {
messageReader(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
Jackson2JsonEncoder jsonEncoder = new Jackson2JsonEncoder();
messageWriter(new Jackson2ServerHttpMessageWriter(jsonEncoder));
messageWriter(new EncoderHttpMessageWriter<>(jsonEncoder));
messageWriter(
new ServerSentEventHttpMessageWriter(Collections.singletonList(jsonEncoder)));
}

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

@ -32,7 +32,6 @@ import org.springframework.core.ReactiveAdapterRegistry; @@ -32,7 +32,6 @@ import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
@ -49,7 +48,7 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException; @@ -49,7 +48,7 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
/**
* Abstract base class for argument resolvers that resolve method arguments
* by reading the request body with an {@link HttpMessageReader}.
* by reading the request body with an {@link ServerHttpMessageReader}.
*
* <p>Applies validation if the method argument is annotated with
* {@code @javax.validation.Valid} or
@ -61,16 +60,16 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException; @@ -61,16 +60,16 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
*/
public abstract class AbstractMessageReaderArgumentResolver extends HandlerMethodArgumentResolverSupport {
private final List<HttpMessageReader<?>> messageReaders;
private final List<ServerHttpMessageReader<?>> messageReaders;
private final List<MediaType> supportedMediaTypes;
/**
* Constructor with {@link HttpMessageReader}'s and a {@link Validator}.
* Constructor with {@link ServerHttpMessageReader}'s and a {@link Validator}.
* @param readers readers to convert from the request body
*/
protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> readers) {
protected AbstractMessageReaderArgumentResolver(List<ServerHttpMessageReader<?>> readers) {
this(readers, new ReactiveAdapterRegistry());
}
@ -79,7 +78,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho @@ -79,7 +78,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
* @param messageReaders readers to convert from the request body
* @param adapterRegistry for adapting to other reactive types from Flux and Mono
*/
protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> messageReaders,
protected AbstractMessageReaderArgumentResolver(List<ServerHttpMessageReader<?>> messageReaders,
ReactiveAdapterRegistry adapterRegistry) {
super(adapterRegistry);
@ -95,7 +94,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho @@ -95,7 +94,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
/**
* Return the configured message converters.
*/
public List<HttpMessageReader<?>> getMessageReaders() {
public List<ServerHttpMessageReader<?>> getMessageReaders() {
return this.messageReaders;
}
@ -114,19 +113,12 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho @@ -114,19 +113,12 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
mediaType = MediaType.APPLICATION_OCTET_STREAM;
}
for (HttpMessageReader<?> reader : getMessageReaders()) {
for (ServerHttpMessageReader<?> reader : getMessageReaders()) {
if (reader.canRead(elementType, mediaType)) {
Map<String, Object> readHints = Collections.emptyMap();
if (adapter != null && adapter.isMultiValue()) {
Flux<?> flux;
if (reader instanceof ServerHttpMessageReader) {
ServerHttpMessageReader<?> serverReader = ((ServerHttpMessageReader<?>) reader);
flux = serverReader.read(bodyType, elementType, request, response, readHints);
}
else {
flux = reader.read(elementType, request, readHints);
}
Flux<?> flux = reader.read(bodyType, elementType, request, response, readHints);
flux = flux.onErrorResumeWith(ex -> Flux.error(getReadError(bodyParameter, ex)));
if (isBodyRequired || !adapter.supportsEmpty()) {
flux = flux.switchIfEmpty(Flux.error(getRequiredBodyError(bodyParameter)));
@ -139,14 +131,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho @@ -139,14 +131,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
return Mono.just(adapter.fromPublisher(flux));
}
else {
Mono<?> mono;
if (reader instanceof ServerHttpMessageReader) {
ServerHttpMessageReader<?> serverReader = (ServerHttpMessageReader<?>) reader;
mono = serverReader.readMono(bodyType, elementType, request, response, readHints);
}
else {
mono = reader.readMono(elementType, request, readHints);
}
Mono<?> mono = reader.readMono(bodyType, elementType, request, response, readHints);
mono = mono.otherwise(ex -> Mono.error(getReadError(bodyParameter, ex)));
if (isBodyRequired || (adapter != null && !adapter.supportsEmpty())) {
mono = mono.otherwiseIfEmpty(Mono.error(getRequiredBodyError(bodyParameter)));

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

@ -27,7 +27,6 @@ import org.springframework.core.ReactiveAdapter; @@ -27,7 +27,6 @@ import org.springframework.core.ReactiveAdapter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.ResolvableType;
import org.springframework.http.MediaType;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
@ -39,24 +38,24 @@ import org.springframework.web.server.ServerWebExchange; @@ -39,24 +38,24 @@ import org.springframework.web.server.ServerWebExchange;
/**
* Abstract base class for result handlers that handle return values by writing
* to the response with {@link HttpMessageWriter}.
* to the response with {@link ServerHttpMessageWriter}.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public abstract class AbstractMessageWriterResultHandler extends HandlerResultHandlerSupport {
private final List<HttpMessageWriter<?>> messageWriters;
private final List<ServerHttpMessageWriter<?>> messageWriters;
/**
* Constructor with {@link HttpMessageWriter}s and a
* Constructor with {@link ServerHttpMessageWriter}s and a
* {@code RequestedContentTypeResolver}.
*
* @param messageWriters for serializing Objects to the response body stream
* @param contentTypeResolver for resolving the requested content type
*/
protected AbstractMessageWriterResultHandler(List<HttpMessageWriter<?>> messageWriters,
protected AbstractMessageWriterResultHandler(List<ServerHttpMessageWriter<?>> messageWriters,
RequestedContentTypeResolver contentTypeResolver) {
super(contentTypeResolver);
@ -72,7 +71,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa @@ -72,7 +71,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
* @param adapterRegistry for adapting other reactive types (e.g. rx.Observable,
* rx.Single, etc.) to Flux or Mono
*/
protected AbstractMessageWriterResultHandler(List<HttpMessageWriter<?>> messageWriters,
protected AbstractMessageWriterResultHandler(List<ServerHttpMessageWriter<?>> messageWriters,
RequestedContentTypeResolver contentTypeResolver,
ReactiveAdapterRegistry adapterRegistry) {
@ -85,7 +84,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa @@ -85,7 +84,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
/**
* Return the configured message converters.
*/
public List<HttpMessageWriter<?>> getMessageWriters() {
public List<ServerHttpMessageWriter<?>> getMessageWriters() {
return this.messageWriters;
}
@ -116,13 +115,10 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa @@ -116,13 +115,10 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
ServerHttpResponse response = exchange.getResponse();
MediaType bestMediaType = selectMediaType(exchange, () -> getProducibleMediaTypes(elementType));
if (bestMediaType != null) {
for (HttpMessageWriter<?> messageWriter : getMessageWriters()) {
if (messageWriter.canWrite(elementType, bestMediaType)) {
return (messageWriter instanceof ServerHttpMessageWriter ?
((ServerHttpMessageWriter<?>) messageWriter).write((Publisher) publisher,
bodyType, elementType, bestMediaType, request, response, Collections.emptyMap()) :
messageWriter.write((Publisher) publisher, elementType,
bestMediaType, response, Collections.emptyMap()));
for (ServerHttpMessageWriter<?> writer : getMessageWriters()) {
if (writer.canWrite(elementType, bestMediaType)) {
return writer.write((Publisher) publisher, bodyType, elementType,
bestMediaType, request, response, Collections.emptyMap());
}
}
}

6
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolver.java

@ -24,7 +24,7 @@ import org.springframework.core.MethodParameter; @@ -24,7 +24,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.HttpEntity;
import org.springframework.http.RequestEntity;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
@ -42,7 +42,9 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes @@ -42,7 +42,9 @@ public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentRes
implements HandlerMethodArgumentResolver {
public HttpEntityArgumentResolver(List<HttpMessageReader<?>> readers, ReactiveAdapterRegistry registry) {
public HttpEntityArgumentResolver(List<ServerHttpMessageReader<?>> readers,
ReactiveAdapterRegistry registry) {
super(readers, registry);
}

6
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolver.java

@ -22,7 +22,7 @@ import reactor.core.publisher.Mono; @@ -22,7 +22,7 @@ import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
@ -47,7 +47,9 @@ public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentRe @@ -47,7 +47,9 @@ public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentRe
implements HandlerMethodArgumentResolver {
public RequestBodyArgumentResolver(List<HttpMessageReader<?>> readers, ReactiveAdapterRegistry registry) {
public RequestBodyArgumentResolver(List<ServerHttpMessageReader<?>> readers,
ReactiveAdapterRegistry registry) {
super(readers, registry);
}

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

@ -44,7 +44,7 @@ import org.springframework.core.codec.ByteBufferDecoder; @@ -44,7 +44,7 @@ import org.springframework.core.codec.ByteBufferDecoder;
import org.springframework.core.codec.DataBufferDecoder;
import org.springframework.core.codec.StringDecoder;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.InitBinder;
@ -76,7 +76,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @@ -76,7 +76,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
private static final Log logger = LogFactory.getLog(RequestMappingHandlerAdapter.class);
private final List<HttpMessageReader<?>> messageReaders = new ArrayList<>(10);
private final List<ServerHttpMessageReader<?>> messageReaders = new ArrayList<>(10);
private WebBindingInitializer webBindingInitializer;
@ -124,7 +124,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @@ -124,7 +124,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
/**
* Configure message readers to de-serialize the request body with.
*/
public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
public void setMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
this.messageReaders.clear();
this.messageReaders.addAll(messageReaders);
}
@ -132,7 +132,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @@ -132,7 +132,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
/**
* Return the configured message readers.
*/
public List<HttpMessageReader<?>> getMessageReaders() {
public List<ServerHttpMessageReader<?>> getMessageReaders() {
return this.messageReaders;
}

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

@ -23,7 +23,7 @@ import reactor.core.publisher.Mono; @@ -23,7 +23,7 @@ import reactor.core.publisher.Mono;
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
@ -34,7 +34,7 @@ import org.springframework.web.server.ServerWebExchange; @@ -34,7 +34,7 @@ import org.springframework.web.server.ServerWebExchange;
/**
* {@code HandlerResultHandler} that handles return values from methods annotated
* with {@code @ResponseBody} writing to the body of the request or response with
* an {@link HttpMessageWriter}.
* an {@link ServerHttpMessageWriter}.
*
* <p>By default the order for this result handler is set to 100. As it detects
* the presence of {@code @ResponseBody} it should be ordered after result
@ -56,7 +56,7 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle @@ -56,7 +56,7 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
* @param writers writers for serializing to the response body
* @param resolver to determine the requested content type
*/
public ResponseBodyResultHandler(List<HttpMessageWriter<?>> writers,
public ResponseBodyResultHandler(List<ServerHttpMessageWriter<?>> writers,
RequestedContentTypeResolver resolver) {
this(writers, resolver, new ReactiveAdapterRegistry());
@ -68,7 +68,7 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle @@ -68,7 +68,7 @@ public class ResponseBodyResultHandler extends AbstractMessageWriterResultHandle
* @param resolver to determine the requested content type
* @param registry for adaptation to reactive types
*/
public ResponseBodyResultHandler(List<HttpMessageWriter<?>> writers,
public ResponseBodyResultHandler(List<ServerHttpMessageWriter<?>> writers,
RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry) {
super(writers, resolver, registry);

6
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandler.java

@ -30,7 +30,7 @@ import org.springframework.http.HttpHeaders; @@ -30,7 +30,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.util.Assert;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
@ -57,7 +57,7 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand @@ -57,7 +57,7 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
* @param writers writers for serializing to the response body
* @param resolver to determine the requested content type
*/
public ResponseEntityResultHandler(List<HttpMessageWriter<?>> writers,
public ResponseEntityResultHandler(List<ServerHttpMessageWriter<?>> writers,
RequestedContentTypeResolver resolver) {
this(writers, resolver, new ReactiveAdapterRegistry());
@ -69,7 +69,7 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand @@ -69,7 +69,7 @@ public class ResponseEntityResultHandler extends AbstractMessageWriterResultHand
* @param resolver to determine the requested content type
* @param registry for adaptation to reactive types
*/
public ResponseEntityResultHandler(List<HttpMessageWriter<?>> writers,
public ResponseEntityResultHandler(List<ServerHttpMessageWriter<?>> writers,
RequestedContentTypeResolver resolver, ReactiveAdapterRegistry registry) {
super(writers, resolver, registry);

8
spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java

@ -30,8 +30,8 @@ import org.mockito.MockitoAnnotations; @@ -30,8 +30,8 @@ import org.mockito.MockitoAnnotations;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
@ -58,10 +58,10 @@ public class DelegatingWebFluxConfigurationTests { @@ -58,10 +58,10 @@ public class DelegatingWebFluxConfigurationTests {
private WebFluxConfigurer webFluxConfigurer;
@Captor
private ArgumentCaptor<List<HttpMessageReader<?>>> readers;
private ArgumentCaptor<List<ServerHttpMessageReader<?>>> readers;
@Captor
private ArgumentCaptor<List<HttpMessageWriter<?>>> writers;
private ArgumentCaptor<List<ServerHttpMessageWriter<?>>> writers;
@Captor
private ArgumentCaptor<FormatterRegistry> formatterRegistry;

24
spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java

@ -36,8 +36,8 @@ import org.springframework.core.io.Resource; @@ -36,8 +36,8 @@ import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
@ -127,7 +127,7 @@ public class WebFluxConfigurationSupportTests { @@ -127,7 +127,7 @@ public class WebFluxConfigurationSupportTests {
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
assertNotNull(adapter);
List<HttpMessageReader<?>> readers = adapter.getMessageReaders();
List<ServerHttpMessageReader<?>> readers = adapter.getMessageReaders();
assertEquals(7, readers.size());
assertHasMessageReader(readers, byte[].class, APPLICATION_OCTET_STREAM);
@ -160,7 +160,7 @@ public class WebFluxConfigurationSupportTests { @@ -160,7 +160,7 @@ public class WebFluxConfigurationSupportTests {
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
assertNotNull(adapter);
List<HttpMessageReader<?>> messageReaders = adapter.getMessageReaders();
List<ServerHttpMessageReader<?>> messageReaders = adapter.getMessageReaders();
assertEquals(2, messageReaders.size());
assertHasMessageReader(messageReaders, String.class, TEXT_PLAIN);
@ -177,7 +177,7 @@ public class WebFluxConfigurationSupportTests { @@ -177,7 +177,7 @@ public class WebFluxConfigurationSupportTests {
assertEquals(0, handler.getOrder());
List<HttpMessageWriter<?>> writers = handler.getMessageWriters();
List<ServerHttpMessageWriter<?>> writers = handler.getMessageWriters();
assertEquals(8, writers.size());
assertHasMessageWriter(writers, byte[].class, APPLICATION_OCTET_STREAM);
@ -203,7 +203,7 @@ public class WebFluxConfigurationSupportTests { @@ -203,7 +203,7 @@ public class WebFluxConfigurationSupportTests {
assertEquals(100, handler.getOrder());
List<HttpMessageWriter<?>> writers = handler.getMessageWriters();
List<ServerHttpMessageWriter<?>> writers = handler.getMessageWriters();
assertEquals(8, writers.size());
assertHasMessageWriter(writers, byte[].class, APPLICATION_OCTET_STREAM);
@ -259,12 +259,12 @@ public class WebFluxConfigurationSupportTests { @@ -259,12 +259,12 @@ public class WebFluxConfigurationSupportTests {
}
private void assertHasMessageReader(List<HttpMessageReader<?>> readers, Class<?> clazz, MediaType mediaType) {
private void assertHasMessageReader(List<ServerHttpMessageReader<?>> readers, Class<?> clazz, MediaType mediaType) {
ResolvableType type = ResolvableType.forClass(clazz);
assertTrue(readers.stream().anyMatch(c -> mediaType == null || c.canRead(type, mediaType)));
}
private void assertHasMessageWriter(List<HttpMessageWriter<?>> writers, Class<?> clazz, MediaType mediaType) {
private void assertHasMessageWriter(List<ServerHttpMessageWriter<?>> writers, Class<?> clazz, MediaType mediaType) {
ResolvableType type = ResolvableType.forClass(clazz);
assertTrue(writers.stream().anyMatch(c -> mediaType == null || c.canWrite(type, mediaType)));
}
@ -297,22 +297,22 @@ public class WebFluxConfigurationSupportTests { @@ -297,22 +297,22 @@ public class WebFluxConfigurationSupportTests {
static class CustomMessageConverterConfig extends WebFluxConfigurationSupport {
@Override
protected void configureMessageReaders(List<HttpMessageReader<?>> messageReaders) {
protected void configureMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
messageReaders.add(new DecoderHttpMessageReader<>(new StringDecoder()));
}
@Override
protected void configureMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
protected void configureMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
messageWriters.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
}
@Override
protected void extendMessageReaders(List<HttpMessageReader<?>> messageReaders) {
protected void extendMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
messageReaders.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder()));
}
@Override
protected void extendMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
protected void extendMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
messageWriters.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
}
}

6
spring-webflux/src/test/java/org/springframework/web/reactive/function/client/ExchangeStrategiesTests.java

@ -97,7 +97,7 @@ public class ExchangeStrategiesTests { @@ -97,7 +97,7 @@ public class ExchangeStrategiesTests {
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType type,
MediaType contentType,
ReactiveHttpOutputMessage outputMessage,
ReactiveHttpOutputMessage message,
Map<String, Object> hints) {
return Mono.empty();
}
@ -117,13 +117,13 @@ public class ExchangeStrategiesTests { @@ -117,13 +117,13 @@ public class ExchangeStrategiesTests {
}
@Override
public Flux<Object> read(ResolvableType type, ReactiveHttpInputMessage inputMessage,
public Flux<Object> read(ResolvableType type, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
return Flux.empty();
}
@Override
public Mono<Object> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage,
public Mono<Object> readMono(ResolvableType type, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
return Mono.empty();
}

11
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DispatcherHandlerIntegrationTests.java

@ -49,9 +49,10 @@ import org.springframework.web.reactive.function.server.support.ServerResponseRe @@ -49,9 +49,10 @@ import org.springframework.web.reactive.function.server.support.ServerResponseRe
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import static org.junit.Assert.*;
import static org.springframework.web.reactive.function.BodyInserters.*;
import static org.springframework.web.reactive.function.server.RouterFunctions.*;
import static org.junit.Assert.assertEquals;
import static org.springframework.web.reactive.function.BodyInserters.fromObject;
import static org.springframework.web.reactive.function.BodyInserters.fromPublisher;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
/**
* Tests the use of {@link HandlerFunction} and {@link RouterFunction} in a
@ -123,12 +124,12 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr @@ -123,12 +124,12 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
new HandlerStrategies() {
@Override
public Supplier<Stream<HttpMessageReader<?>>> messageReaders() {
return () -> getMessageReaders().stream();
return () -> getMessageReaders().stream().map(reader -> (HttpMessageReader<?>) reader);
}
@Override
public Supplier<Stream<HttpMessageWriter<?>>> messageWriters() {
return () -> getMessageWriters().stream();
return () -> getMessageWriters().stream().map(writer -> (HttpMessageWriter<?>) writer);
}
@Override

6
spring-webflux/src/test/java/org/springframework/web/reactive/function/server/HandlerStrategiesTests.java

@ -99,7 +99,7 @@ public class HandlerStrategiesTests { @@ -99,7 +99,7 @@ public class HandlerStrategiesTests {
@Override
public Mono<Void> write(Publisher<?> inputStream, ResolvableType type,
MediaType contentType,
ReactiveHttpOutputMessage outputMessage,
ReactiveHttpOutputMessage message,
Map<String, Object> hints) {
return Mono.empty();
}
@ -119,13 +119,13 @@ public class HandlerStrategiesTests { @@ -119,13 +119,13 @@ public class HandlerStrategiesTests {
}
@Override
public Flux<Object> read(ResolvableType type, ReactiveHttpInputMessage inputMessage,
public Flux<Object> read(ResolvableType type, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
return Flux.empty();
}
@Override
public Mono<Object> readMono(ResolvableType type, ReactiveHttpInputMessage inputMessage,
public Mono<Object> readMono(ResolvableType type, ReactiveHttpInputMessage message,
Map<String, Object> hints) {
return Mono.empty();
}

4
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/HttpEntityArgumentResolverTests.java

@ -39,7 +39,7 @@ import org.springframework.core.codec.StringDecoder; @@ -39,7 +39,7 @@ import org.springframework.core.codec.StringDecoder;
import org.springframework.http.HttpEntity;
import org.springframework.http.RequestEntity;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
import org.springframework.util.ObjectUtils;
import org.springframework.web.method.ResolvableMethod;
@ -73,7 +73,7 @@ public class HttpEntityArgumentResolverTests { @@ -73,7 +73,7 @@ public class HttpEntityArgumentResolverTests {
private HttpEntityArgumentResolver createResolver() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
List<ServerHttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
return new HttpEntityArgumentResolver(readers, new ReactiveAdapterRegistry());
}

6
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageReaderArgumentResolverTests.java

@ -43,15 +43,15 @@ import org.springframework.core.ResolvableType; @@ -43,15 +43,15 @@ import org.springframework.core.ResolvableType;
import org.springframework.core.codec.Decoder;
import org.springframework.http.MediaType;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.http.codec.json.Jackson2JsonDecoder;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.method.ResolvableMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.ServerWebInputException;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
@ -305,7 +305,7 @@ public class MessageReaderArgumentResolverTests { @@ -305,7 +305,7 @@ public class MessageReaderArgumentResolverTests {
@SuppressWarnings("Convert2MethodRef")
private AbstractMessageReaderArgumentResolver resolver(Decoder<?>... decoders) {
List<HttpMessageReader<?>> readers = new ArrayList<>();
List<ServerHttpMessageReader<?>> readers = new ArrayList<>();
Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder)));
return new AbstractMessageReaderArgumentResolver(readers) {};
}

8
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/MessageWriterResultHandlerTests.java

@ -42,8 +42,8 @@ import org.springframework.core.codec.CharSequenceEncoder; @@ -42,8 +42,8 @@ import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
@ -71,8 +71,8 @@ public class MessageWriterResultHandlerTests { @@ -71,8 +71,8 @@ public class MessageWriterResultHandlerTests {
private final MockServerWebExchange exchange = MockServerHttpRequest.get("/path").toExchange();
private AbstractMessageWriterResultHandler initResultHandler(HttpMessageWriter<?>... writers) {
List<HttpMessageWriter<?>> writerList;
private AbstractMessageWriterResultHandler initResultHandler(ServerHttpMessageWriter<?>... writers) {
List<ServerHttpMessageWriter<?>> writerList;
if (ObjectUtils.isEmpty(writers)) {
writerList = new ArrayList<>();
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
@ -141,7 +141,7 @@ public class MessageWriterResultHandlerTests { @@ -141,7 +141,7 @@ public class MessageWriterResultHandlerTests {
ByteArrayOutputStream body = new ByteArrayOutputStream();
MethodParameter type = on(TestController.class).resolveReturnType(OutputStream.class);
HttpMessageWriter<?> writer = new EncoderHttpMessageWriter<>(new ByteBufferEncoder());
ServerHttpMessageWriter<?> writer = new EncoderHttpMessageWriter<>(new ByteBufferEncoder());
Mono<Void> mono = initResultHandler(writer).writeBody(body, type, this.exchange);
StepVerifier.create(mono).expectError(IllegalStateException.class).verify();

4
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestBodyArgumentResolverTests.java

@ -35,7 +35,7 @@ import org.springframework.core.MethodParameter; @@ -35,7 +35,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.codec.StringDecoder;
import org.springframework.http.codec.DecoderHttpMessageReader;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerHttpMessageReader;
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.method.ResolvableMethod;
@ -66,7 +66,7 @@ public class RequestBodyArgumentResolverTests { @@ -66,7 +66,7 @@ public class RequestBodyArgumentResolverTests {
@Before
public void setup() {
List<HttpMessageReader<?>> readers = new ArrayList<>();
List<ServerHttpMessageReader<?>> readers = new ArrayList<>();
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
this.resolver = new RequestBodyArgumentResolver(readers, new ReactiveAdapterRegistry());
}

4
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandlerTests.java

@ -29,8 +29,8 @@ import rx.Single; @@ -29,8 +29,8 @@ import rx.Single;
import org.springframework.core.codec.ByteBufferEncoder;
import org.springframework.core.codec.CharSequenceEncoder;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.stereotype.Controller;
@ -64,7 +64,7 @@ public class ResponseBodyResultHandlerTests { @@ -64,7 +64,7 @@ public class ResponseBodyResultHandlerTests {
@Before
public void setup() throws Exception {
List<HttpMessageWriter<?>> writerList = new ArrayList<>(5);
List<ServerHttpMessageWriter<?>> writerList = new ArrayList<>(5);
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
writerList.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
writerList.add(new ResourceHttpMessageWriter());

6
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ResponseEntityResultHandlerTests.java

@ -43,8 +43,8 @@ import org.springframework.http.HttpHeaders; @@ -43,8 +43,8 @@ import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.codec.EncoderHttpMessageWriter;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ResourceHttpMessageWriter;
import org.springframework.http.codec.ServerHttpMessageWriter;
import org.springframework.http.codec.json.Jackson2JsonEncoder;
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
import org.springframework.mock.http.server.reactive.test.MockServerWebExchange;
@ -83,8 +83,8 @@ public class ResponseEntityResultHandlerTests { @@ -83,8 +83,8 @@ public class ResponseEntityResultHandlerTests {
this.resultHandler = createHandler();
}
private ResponseEntityResultHandler createHandler(HttpMessageWriter<?>... writers) {
List<HttpMessageWriter<?>> writerList;
private ResponseEntityResultHandler createHandler(ServerHttpMessageWriter<?>... writers) {
List<ServerHttpMessageWriter<?>> writerList;
if (ObjectUtils.isEmpty(writers)) {
writerList = new ArrayList<>();
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));

Loading…
Cancel
Save