Merge refactoring steps in HTTP codec package
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
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> {
|
||||
}
|
||||
|
||||
@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> {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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> {
|
||||
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
|
||||
@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> {
|
||||
}
|
||||
|
||||
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> {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
.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));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
List<MediaType> getReadableMediaTypes();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
boolean canRead(ResolvableType elementType, MediaType mediaType);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints);
|
||||
Flux<T> read(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints);
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
*/
|
||||
Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage inputMessage, Map<String, Object> hints);
|
||||
Mono<T> readMono(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
|
||||
*/
|
||||
List<MediaType> getReadableMediaTypes();
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
List<MediaType> getWritableMediaTypes();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
boolean canWrite(ResolvableType elementType, MediaType mediaType);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
*/
|
||||
Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType elementType,
|
||||
MediaType mediaType, ReactiveHttpOutputMessage outputMessage, Map<String, Object> hints);
|
||||
MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints);
|
||||
|
||||
/**
|
||||
* Return the list of {@link MediaType} objects that can be written by this converter.
|
||||
* @return the list of supported readable media types
|
||||
*/
|
||||
List<MediaType> getWritableMediaTypes();
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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);
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
* @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
|
||||
|
||||
@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
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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;
|
||||
* @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
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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;
|
||||
* @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
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@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
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
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 {
|
||||
* <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 {
|
||||
* {@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 {
|
||||
* {@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 {
|
||||
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 {
|
||||
* 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 {
|
||||
* <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 {
|
||||
* {@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 {
|
||||
}
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
* 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 {
|
||||
* 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) {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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 {
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
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)));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
*/
|
||||
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
|
||||
* @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
|
||||
/**
|
||||
* 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
|
||||
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
|
||||
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)));
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @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
|
||||
/**
|
||||
* 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
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
implements HandlerMethodArgumentResolver {
|
||||
|
||||
|
||||
public HttpEntityArgumentResolver(List<HttpMessageReader<?>> readers, ReactiveAdapterRegistry registry) {
|
||||
public HttpEntityArgumentResolver(List<ServerHttpMessageReader<?>> readers,
|
||||
ReactiveAdapterRegistry registry) {
|
||||
|
||||
super(readers, registry);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
implements HandlerMethodArgumentResolver {
|
||||
|
||||
|
||||
public RequestBodyArgumentResolver(List<HttpMessageReader<?>> readers, ReactiveAdapterRegistry registry) {
|
||||
public RequestBodyArgumentResolver(List<ServerHttpMessageReader<?>> readers,
|
||||
ReactiveAdapterRegistry registry) {
|
||||
|
||||
super(readers, registry);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
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
|
||||
/**
|
||||
* 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
|
||||
/**
|
||||
* Return the configured message readers.
|
||||
*/
|
||||
public List<HttpMessageReader<?>> getMessageReaders() {
|
||||
public List<ServerHttpMessageReader<?>> getMessageReaders() {
|
||||
return this.messageReaders;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
/**
|
||||
* {@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
|
||||
* @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
|
||||
* @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);
|
||||
|
||||
@@ -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
|
||||
* @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
|
||||
* @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);
|
||||
|
||||
@@ -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 {
|
||||
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;
|
||||
|
||||
@@ -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 {
|
||||
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 {
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
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
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@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) {};
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
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 {
|
||||
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();
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@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());
|
||||
|
||||
@@ -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 {
|
||||
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()));
|
||||
|
||||
Reference in New Issue
Block a user