Merge ServerCodecConfigurer + refactoring
This commit is contained in:
@@ -25,8 +25,8 @@ import java.util.function.Consumer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.http.codec.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
@@ -85,14 +85,8 @@ class DefaultControllerSpec extends AbstractMockServerSpec<WebTestClient.Control
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultControllerSpec messageReaders(Consumer<List<ServerHttpMessageReader<?>>> consumer) {
|
||||
this.configurer.readersConsumer = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultControllerSpec messageWriters(Consumer<List<ServerHttpMessageWriter<?>>> consumer) {
|
||||
this.configurer.writersConsumer = consumer;
|
||||
public DefaultControllerSpec httpMessageCodecs(Consumer<ServerCodecConfigurer> consumer) {
|
||||
this.configurer.messageCodecsConsumer = consumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -145,9 +139,9 @@ class DefaultControllerSpec extends AbstractMockServerSpec<WebTestClient.Control
|
||||
|
||||
private Consumer<PathMatchConfigurer> pathMatchConsumer;
|
||||
|
||||
private Consumer<List<ServerHttpMessageReader<?>>> readersConsumer;
|
||||
private Consumer<ServerCodecConfigurer> messageCodecsConsumer;
|
||||
|
||||
private Consumer<List<ServerHttpMessageWriter<?>>> writersConsumer;
|
||||
private Consumer<List<HttpMessageWriter<?>>> writersConsumer;
|
||||
|
||||
private Consumer<FormatterRegistry> formattersConsumer;
|
||||
|
||||
@@ -178,16 +172,9 @@ class DefaultControllerSpec extends AbstractMockServerSpec<WebTestClient.Control
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendMessageReaders(List<ServerHttpMessageReader<?>> readers) {
|
||||
if (this.readersConsumer != null) {
|
||||
this.readersConsumer.accept(readers);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
|
||||
if (this.writersConsumer != null) {
|
||||
this.writersConsumer.accept(writers);
|
||||
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
|
||||
if (this.messageCodecsConsumer != null) {
|
||||
this.messageCodecsConsumer.accept(configurer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,7 @@ import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.client.reactive.ClientHttpRequest;
|
||||
import org.springframework.http.codec.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
|
||||
@@ -244,16 +243,10 @@ public interface WebTestClient {
|
||||
ControllerSpec pathMatching(Consumer<PathMatchConfigurer> consumer);
|
||||
|
||||
/**
|
||||
* Modify or extend the list of built-in message readers.
|
||||
* @see WebFluxConfigurer#configureMessageReaders
|
||||
* Modify or extend the list of built-in message readers and writers.
|
||||
* @see WebFluxConfigurer#configureHttpMessageCodecs
|
||||
*/
|
||||
ControllerSpec messageReaders(Consumer<List<ServerHttpMessageReader<?>>> readers);
|
||||
|
||||
/**
|
||||
* Modify or extend the list of built-in message writers.
|
||||
* @see WebFluxConfigurer#configureMessageWriters
|
||||
*/
|
||||
ControllerSpec messageWriters(Consumer<List<ServerHttpMessageWriter<?>>> writers);
|
||||
ControllerSpec httpMessageCodecs(Consumer<ServerCodecConfigurer> configurer);
|
||||
|
||||
/**
|
||||
* Register formatters and converters to use for type conversion.
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* {@code HttpMessageReader} that wraps and delegates to a {@link Decoder}.
|
||||
*
|
||||
* <p>Also a {@code ServerHttpMessageReader} that pre-resolves decoding hints
|
||||
* <p>Also a {@code HttpMessageReader} that pre-resolves decoding hints
|
||||
* from the extra information available on the server side such as the request
|
||||
* or controller method parameter annotations.
|
||||
*
|
||||
@@ -45,7 +45,7 @@ import org.springframework.util.Assert;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class DecoderHttpMessageReader<T> implements ServerHttpMessageReader<T> {
|
||||
public class DecoderHttpMessageReader<T> implements HttpMessageReader<T> {
|
||||
|
||||
private final Decoder<T> decoder;
|
||||
|
||||
@@ -102,7 +102,7 @@ public class DecoderHttpMessageReader<T> implements ServerHttpMessageReader<T> {
|
||||
}
|
||||
|
||||
|
||||
// ServerHttpMessageReader...
|
||||
// Server-side only...
|
||||
|
||||
@Override
|
||||
public Flux<T> read(ResolvableType actualType, ResolvableType elementType,
|
||||
@@ -129,13 +129,13 @@ public class DecoderHttpMessageReader<T> implements ServerHttpMessageReader<T> {
|
||||
/**
|
||||
* 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 HttpDecoder}.
|
||||
* the decoder if it is an instance of {@link HttpMessageDecoder}.
|
||||
*/
|
||||
protected Map<String, Object> getReadHints(ResolvableType streamType,
|
||||
ResolvableType elementType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
if (this.decoder instanceof HttpDecoder) {
|
||||
HttpDecoder<?> httpDecoder = (HttpDecoder<?>) this.decoder;
|
||||
if (this.decoder instanceof HttpMessageDecoder) {
|
||||
HttpMessageDecoder<?> httpDecoder = (HttpMessageDecoder<?>) this.decoder;
|
||||
return httpDecoder.getDecodeHints(streamType, elementType, request, response);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
|
||||
@@ -37,7 +37,7 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* {@code HttpMessageWriter} that wraps and delegates to a {@link Encoder}.
|
||||
*
|
||||
* <p>Also a {@code ServerHttpMessageWriter} that pre-resolves encoding hints
|
||||
* <p>Also a {@code HttpMessageWriter} that pre-resolves encoding hints
|
||||
* from the extra information available on the server side such as the request
|
||||
* or controller method annotations.
|
||||
*
|
||||
@@ -46,7 +46,7 @@ import org.springframework.util.Assert;
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class EncoderHttpMessageWriter<T> implements ServerHttpMessageWriter<T> {
|
||||
public class EncoderHttpMessageWriter<T> implements HttpMessageWriter<T> {
|
||||
|
||||
private final Encoder<T> encoder;
|
||||
|
||||
@@ -130,13 +130,13 @@ public class EncoderHttpMessageWriter<T> implements ServerHttpMessageWriter<T> {
|
||||
}
|
||||
|
||||
private boolean isStreamingMediaType(MediaType contentType) {
|
||||
return this.encoder instanceof HttpEncoder &&
|
||||
((HttpEncoder<?>) this.encoder).getStreamingMediaTypes().stream()
|
||||
return this.encoder instanceof HttpMessageEncoder &&
|
||||
((HttpMessageEncoder<?>) this.encoder).getStreamingMediaTypes().stream()
|
||||
.anyMatch(contentType::isCompatibleWith);
|
||||
}
|
||||
|
||||
|
||||
// ServerHttpMessageWriter...
|
||||
// Server side only...
|
||||
|
||||
@Override
|
||||
public Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType actualType,
|
||||
@@ -153,13 +153,13 @@ public class EncoderHttpMessageWriter<T> implements ServerHttpMessageWriter<T> {
|
||||
/**
|
||||
* 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 HttpEncoder}.
|
||||
* the encoder if it is an instance of {@link HttpMessageEncoder}.
|
||||
*/
|
||||
protected Map<String, Object> getWriteHints(ResolvableType streamType, ResolvableType elementType,
|
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
if (this.encoder instanceof HttpEncoder) {
|
||||
HttpEncoder<?> httpEncoder = (HttpEncoder<?>) this.encoder;
|
||||
if (this.encoder instanceof HttpMessageEncoder) {
|
||||
HttpMessageEncoder<?> httpEncoder = (HttpMessageEncoder<?>) this.encoder;
|
||||
return httpEncoder.getEncodeHints(streamType, elementType, mediaType, request, response);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
|
||||
@@ -25,12 +25,12 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
|
||||
/**
|
||||
* Extension of {@code Decoder} exposing extra methods relevant in the context
|
||||
* of HTTP applications.
|
||||
* of HTTP request or response body decoding.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface HttpDecoder<T> extends Decoder<T> {
|
||||
public interface HttpMessageDecoder<T> extends Decoder<T> {
|
||||
|
||||
/**
|
||||
* Get decoding hints based on the server request or annotations on the
|
||||
@@ -29,12 +29,12 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
|
||||
/**
|
||||
* Extension of {@code Encoder} exposing extra methods relevant in the context
|
||||
* of HTTP applications.
|
||||
* of HTTP request or response body encoding.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface HttpEncoder<T> extends Encoder<T> {
|
||||
public interface HttpMessageEncoder<T> extends Encoder<T> {
|
||||
|
||||
/**
|
||||
* Return "streaming" media types for which flushing should be performed
|
||||
@@ -22,9 +22,12 @@ 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;
|
||||
|
||||
/**
|
||||
* Strategy for reading from a {@link ReactiveHttpInputMessage} and decoding
|
||||
@@ -74,5 +77,44 @@ public interface HttpMessageReader<T> {
|
||||
*/
|
||||
Mono<T> readMono(ResolvableType elementType, ReactiveHttpInputMessage message, Map<String, Object> hints);
|
||||
|
||||
/**
|
||||
* Server-side only alternative to
|
||||
* {@link #read(ResolvableType, ReactiveHttpInputMessage, Map)} with
|
||||
* additional context available.
|
||||
*
|
||||
* @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 decoded stream of elements
|
||||
*/
|
||||
default Flux<T> read(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints) {
|
||||
|
||||
return read(elementType, request, hints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server-side only alternative to
|
||||
* {@link #readMono(ResolvableType, ReactiveHttpInputMessage, Map)} with
|
||||
* additional, context available.
|
||||
*
|
||||
* @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 decoded stream of elements
|
||||
*/
|
||||
default Mono<T> readMono(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints) {
|
||||
|
||||
return readMono(elementType, request, hints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,9 +22,12 @@ 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;
|
||||
|
||||
/**
|
||||
* Strategy for encoding a stream of objects of type {@code <T>} and writing
|
||||
@@ -67,4 +70,26 @@ public interface HttpMessageWriter<T> {
|
||||
MediaType mediaType, ReactiveHttpOutputMessage message, Map<String, Object> hints);
|
||||
|
||||
|
||||
/**
|
||||
* Server-side only alternative to
|
||||
* {@link #write(Publisher, ResolvableType, MediaType, ReactiveHttpOutputMessage, Map)}
|
||||
* with additional context available.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
default Mono<Void> write(Publisher<? extends T> inputStream, ResolvableType actualType,
|
||||
ResolvableType elementType, MediaType mediaType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints) {
|
||||
|
||||
return write(inputStream, elementType, mediaType, response, hints);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ import static java.util.Collections.emptyMap;
|
||||
/**
|
||||
* {@code HttpMessageWriter} that can write a {@link Resource}.
|
||||
*
|
||||
* <p>Also an implementation of {@code ServerHttpMessageWriter} with support
|
||||
* <p>Also an implementation of {@code HttpMessageWriter} with support
|
||||
* for writing one or more {@link ResourceRegion}'s based on the HTTP ranges
|
||||
* specified in the request.
|
||||
*
|
||||
@@ -68,7 +68,7 @@ import static java.util.Collections.emptyMap;
|
||||
* @see ResourceRegionEncoder
|
||||
* @see HttpRange
|
||||
*/
|
||||
public class ResourceHttpMessageWriter implements ServerHttpMessageWriter<Resource> {
|
||||
public class ResourceHttpMessageWriter implements HttpMessageWriter<Resource> {
|
||||
|
||||
private static final ResolvableType REGION_TYPE = ResolvableType.forClass(ResourceRegion.class);
|
||||
|
||||
@@ -102,7 +102,7 @@ public class ResourceHttpMessageWriter implements ServerHttpMessageWriter<Resour
|
||||
}
|
||||
|
||||
|
||||
// HttpMessageWriter (client and server): single Resource
|
||||
// Client or server: single Resource...
|
||||
|
||||
@Override
|
||||
public Mono<Void> write(Publisher<? extends Resource> inputStream, ResolvableType elementType,
|
||||
@@ -171,7 +171,7 @@ public class ResourceHttpMessageWriter implements ServerHttpMessageWriter<Resour
|
||||
}
|
||||
|
||||
|
||||
// ServerHttpMessageWriter (server only): single Resource or sub-regions
|
||||
// Server-side only: single Resource or sub-regions...
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
/*
|
||||
* 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.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.ByteArrayDecoder;
|
||||
import org.springframework.core.codec.ByteArrayEncoder;
|
||||
import org.springframework.core.codec.ByteBufferDecoder;
|
||||
import org.springframework.core.codec.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
import org.springframework.core.codec.DataBufferDecoder;
|
||||
import org.springframework.core.codec.DataBufferEncoder;
|
||||
import org.springframework.core.codec.Decoder;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.ResourceDecoder;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Helps to configure a list of server-side HTTP message readers and writers
|
||||
* with support for built-in defaults and options to register additional custom
|
||||
* readers and writers via {@link #customCodec()}.
|
||||
*
|
||||
* <p>The built-in defaults include basic data types such as
|
||||
* {@link Byte byte[]}, {@link java.nio.ByteBuffer ByteBuffer},
|
||||
* {@link org.springframework.core.io.buffer.DataBuffer DataBuffer},
|
||||
* {@link String}, {@link org.springframework.core.io.Resource Resource},
|
||||
* in addition to JAXB2 and Jackson 2 based on classpath detection, as well as
|
||||
* support for Server-Sent Events. There are options to {@link #defaultCodec()
|
||||
* override} some of the defaults or to have them
|
||||
* {@link #registerDefaults(boolean) turned off} completely.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ServerCodecConfigurer {
|
||||
|
||||
private static final boolean jackson2Present =
|
||||
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
|
||||
ServerCodecConfigurer.class.getClassLoader()) &&
|
||||
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",
|
||||
ServerCodecConfigurer.class.getClassLoader());
|
||||
|
||||
private static final boolean jaxb2Present =
|
||||
ClassUtils.isPresent("javax.xml.bind.Binder", ServerCodecConfigurer.class.getClassLoader());
|
||||
|
||||
|
||||
private final DefaultCodecConfigurer defaultCodecs = new DefaultCodecConfigurer();
|
||||
|
||||
private final CustomCodecConfigurer customCodecs = new CustomCodecConfigurer();
|
||||
|
||||
|
||||
/**
|
||||
* Provide overrides for built-in HTTP message readers and writers.
|
||||
*/
|
||||
public DefaultCodecConfigurer defaultCodec() {
|
||||
return this.defaultCodecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to make default HTTP message reader and writer registrations.
|
||||
* <p>By default this is set to {@code "true"}.
|
||||
*/
|
||||
public void registerDefaults(boolean register) {
|
||||
this.defaultCodec().setSuppressed(!register);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a custom encoder or decoder.
|
||||
*/
|
||||
public CustomCodecConfigurer customCodec() {
|
||||
return this.customCodecs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepare a list of HTTP message readers.
|
||||
*/
|
||||
public List<HttpMessageReader<?>> getReaders() {
|
||||
|
||||
// Built-in, concrete Java type readers
|
||||
List<HttpMessageReader<?>> result = new ArrayList<>();
|
||||
this.defaultCodecs.addReaderTo(result, ByteArrayDecoder.class, ByteArrayDecoder::new);
|
||||
this.defaultCodecs.addReaderTo(result, ByteBufferDecoder.class, ByteBufferDecoder::new);
|
||||
this.defaultCodecs.addReaderTo(result, DataBufferDecoder.class, DataBufferDecoder::new);
|
||||
this.defaultCodecs.addReaderTo(result, ResourceDecoder.class, ResourceDecoder::new);
|
||||
this.defaultCodecs.addStringReaderTextOnlyTo(result);
|
||||
|
||||
// Custom, concrete Java type readers
|
||||
this.customCodecs.addTypedReadersTo(result);
|
||||
|
||||
// Built-in, Object-based readers
|
||||
if (jaxb2Present) {
|
||||
this.defaultCodecs.addReaderTo(result, Jaxb2XmlDecoder.class, Jaxb2XmlDecoder::new);
|
||||
}
|
||||
if (jackson2Present) {
|
||||
this.defaultCodecs.addReaderTo(result, Jackson2JsonDecoder.class, Jackson2JsonDecoder::new);
|
||||
}
|
||||
|
||||
// Custom, Object-based readers
|
||||
this.customCodecs.addObjectReadersTo(result);
|
||||
|
||||
// Potentially overlapping Java types + "*/*"
|
||||
this.defaultCodecs.addStringReaderTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a list of HTTP message writers.
|
||||
*/
|
||||
public List<HttpMessageWriter<?>> getWriters() {
|
||||
|
||||
// Built-in, concrete Java type readers
|
||||
List<HttpMessageWriter<?>> result = new ArrayList<>();
|
||||
this.defaultCodecs.addWriterTo(result, ByteArrayEncoder.class, ByteArrayEncoder::new);
|
||||
this.defaultCodecs.addWriterTo(result, ByteBufferEncoder.class, ByteBufferEncoder::new);
|
||||
this.defaultCodecs.addWriterTo(result, DataBufferEncoder.class, DataBufferEncoder::new);
|
||||
this.defaultCodecs.addWriterTo(result, ResourceHttpMessageWriter::new);
|
||||
this.defaultCodecs.addStringWriterTextPlainOnlyTo(result);
|
||||
|
||||
// Custom, concrete Java type readers
|
||||
this.customCodecs.addTypedWritersTo(result);
|
||||
|
||||
// Built-in, Object-based readers
|
||||
if (jaxb2Present) {
|
||||
this.defaultCodecs.addWriterTo(result, Jaxb2XmlEncoder.class, Jaxb2XmlEncoder::new);
|
||||
}
|
||||
if (jackson2Present) {
|
||||
this.defaultCodecs.addWriterTo(result, Jackson2JsonEncoder.class, Jackson2JsonEncoder::new);
|
||||
}
|
||||
this.defaultCodecs.addSseWriterTo(result);
|
||||
|
||||
// Custom, Object-based readers
|
||||
this.customCodecs.addObjectWritersTo(result);
|
||||
|
||||
// Potentially overlapping Java types + "*/*"
|
||||
this.defaultCodecs.addStringWriterTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A registry and a factory for built-in HTTP message readers and writers.
|
||||
*/
|
||||
public static class DefaultCodecConfigurer {
|
||||
|
||||
private boolean suppressed = false;
|
||||
|
||||
private final Map<Class<?>, HttpMessageReader<?>> readers = new HashMap<>();
|
||||
|
||||
private final Map<Class<?>, HttpMessageWriter<?>> writers = new HashMap<>();
|
||||
|
||||
|
||||
/**
|
||||
* Override the default Jackson {@code Decoder}.
|
||||
* @param decoder the decoder to use
|
||||
*/
|
||||
public void jackson2Decoder(Jackson2JsonDecoder decoder) {
|
||||
this.readers.put(Jackson2JsonDecoder.class, new DecoderHttpMessageReader<>(decoder));
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the default Jackson {@code Encoder} for JSON. Also used for
|
||||
* SSE unless further overridden via {@link #sse(Encoder)}.
|
||||
* @param encoder the encoder to use
|
||||
*/
|
||||
public void jackson2Encoder(Jackson2JsonEncoder encoder) {
|
||||
this.writers.put(Jackson2JsonEncoder.class, new EncoderHttpMessageWriter<>(encoder));
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the {@code Encoder} to use for Server-Sent Events.
|
||||
* <p>By default the {@link #jackson2Encoder} override is used for SSE.
|
||||
* @param encoder the encoder to use
|
||||
*/
|
||||
public void sse(Encoder<?> encoder) {
|
||||
HttpMessageWriter<?> writer = new ServerSentEventHttpMessageWriter(encoder);
|
||||
this.writers.put(ServerSentEventHttpMessageWriter.class, writer);
|
||||
}
|
||||
|
||||
|
||||
// Internal methods for building a list of default readers or writers...
|
||||
|
||||
private void setSuppressed(boolean suppressed) {
|
||||
this.suppressed = suppressed;
|
||||
}
|
||||
|
||||
private <T, D extends Decoder<T>> void addReaderTo(List<HttpMessageReader<?>> result,
|
||||
Class<D> key, Supplier<D> fallback) {
|
||||
|
||||
addReaderTo(result, () -> findReader(key, fallback));
|
||||
}
|
||||
|
||||
private void addReaderTo(List<HttpMessageReader<?>> result,
|
||||
Supplier<HttpMessageReader<?>> reader) {
|
||||
|
||||
if (!this.suppressed) {
|
||||
result.add(reader.get());
|
||||
}
|
||||
}
|
||||
|
||||
private <T, D extends Decoder<T>> DecoderHttpMessageReader<?> findReader(
|
||||
Class<D> key, Supplier<D> fallback) {
|
||||
|
||||
DecoderHttpMessageReader<?> reader = (DecoderHttpMessageReader<?>) this.readers.get(key);
|
||||
return reader != null ? reader : new DecoderHttpMessageReader<>(fallback.get());
|
||||
}
|
||||
|
||||
|
||||
private <T, E extends Encoder<T>> void addWriterTo(List<HttpMessageWriter<?>> result,
|
||||
Class<E> key, Supplier<E> fallback) {
|
||||
|
||||
addWriterTo(result, () -> findWriter(key, fallback));
|
||||
}
|
||||
|
||||
private void addWriterTo(List<HttpMessageWriter<?>> result,
|
||||
Supplier<HttpMessageWriter<?>> writer) {
|
||||
|
||||
if (!this.suppressed) {
|
||||
result.add(writer.get());
|
||||
}
|
||||
}
|
||||
|
||||
private <T, E extends Encoder<T>> EncoderHttpMessageWriter<?> findWriter(
|
||||
Class<E> key, Supplier<E> fallback) {
|
||||
|
||||
EncoderHttpMessageWriter<?> writer = (EncoderHttpMessageWriter<?>) this.writers.get(key);
|
||||
return writer != null ? writer : new EncoderHttpMessageWriter<>(fallback.get());
|
||||
}
|
||||
|
||||
|
||||
private void addStringReaderTextOnlyTo(List<HttpMessageReader<?>> result) {
|
||||
addReaderTo(result, () -> new DecoderHttpMessageReader<>(StringDecoder.textPlainOnly(true)));
|
||||
}
|
||||
|
||||
private void addStringReaderTo(List<HttpMessageReader<?>> result) {
|
||||
addReaderTo(result, () -> new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes(true)));
|
||||
}
|
||||
|
||||
private void addStringWriterTextPlainOnlyTo(List<HttpMessageWriter<?>> result) {
|
||||
addWriterTo(result, () -> new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
|
||||
}
|
||||
|
||||
private void addStringWriterTo(List<HttpMessageWriter<?>> result) {
|
||||
addWriterTo(result, () -> new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
|
||||
}
|
||||
|
||||
private void addSseWriterTo(List<HttpMessageWriter<?>> result) {
|
||||
addWriterTo(result, () -> {
|
||||
HttpMessageWriter<?> writer = this.writers.get(ServerSentEventHttpMessageWriter.class);
|
||||
if (writer != null) {
|
||||
return writer;
|
||||
}
|
||||
if (jackson2Present) {
|
||||
return new ServerSentEventHttpMessageWriter(
|
||||
findWriter(Jackson2JsonEncoder.class, Jackson2JsonEncoder::new).getEncoder());
|
||||
}
|
||||
return new ServerSentEventHttpMessageWriter();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registry and container for custom HTTP message readers and writers.
|
||||
*/
|
||||
public static class CustomCodecConfigurer {
|
||||
|
||||
private final List<HttpMessageReader<?>> typedReaders = new ArrayList<>();
|
||||
|
||||
private final List<HttpMessageWriter<?>> typedWriters = new ArrayList<>();
|
||||
|
||||
private final List<HttpMessageReader<?>> objectReaders = new ArrayList<>();
|
||||
|
||||
private final List<HttpMessageWriter<?>> objectWriters = new ArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* Add a custom {@code Decoder} internally wrapped with
|
||||
* {@link DecoderHttpMessageReader}).
|
||||
*/
|
||||
public void decoder(Decoder<?> decoder) {
|
||||
reader(new DecoderHttpMessageReader<>(decoder));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom {@code Encoder}, internally wrapped with
|
||||
* {@link EncoderHttpMessageWriter}.
|
||||
*/
|
||||
public void encoder(Encoder<?> encoder) {
|
||||
writer(new EncoderHttpMessageWriter<>(encoder));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom {@link HttpMessageReader}. For readers of type
|
||||
* {@link DecoderHttpMessageReader} consider using the shortcut
|
||||
* {@link #decoder(Decoder)} instead.
|
||||
*/
|
||||
public void reader(HttpMessageReader<?> reader) {
|
||||
boolean canReadToObject = reader.canRead(ResolvableType.forClass(Object.class), null);
|
||||
(canReadToObject ? this.objectReaders : this.typedReaders).add(reader);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a custom {@link HttpMessageWriter}. For readers of type
|
||||
* {@link EncoderHttpMessageWriter} consider using the shortcut
|
||||
* {@link #encoder(Encoder)} instead.
|
||||
*/
|
||||
public void writer(HttpMessageWriter<?> writer) {
|
||||
boolean canWriteObject = writer.canWrite(ResolvableType.forClass(Object.class), null);
|
||||
(canWriteObject ? this.objectWriters : this.typedWriters).add(writer);
|
||||
}
|
||||
|
||||
|
||||
// Internal methods for building a list of custom readers or writers...
|
||||
|
||||
private void addTypedReadersTo(List<HttpMessageReader<?>> result) {
|
||||
result.addAll(this.typedReaders);
|
||||
}
|
||||
|
||||
private void addObjectReadersTo(List<HttpMessageReader<?>> result) {
|
||||
result.addAll(this.objectReaders);
|
||||
}
|
||||
|
||||
private void addTypedWritersTo(List<HttpMessageWriter<?>> result) {
|
||||
result.addAll(this.typedWriters);
|
||||
}
|
||||
|
||||
private void addObjectWritersTo(List<HttpMessageWriter<?>> result) {
|
||||
result.addAll(this.objectWriters);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* 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 reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.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> {
|
||||
|
||||
/**
|
||||
* Decode and read the request body to an object stream.
|
||||
*
|
||||
* @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 decoded stream of elements
|
||||
*/
|
||||
Flux<T> read(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints);
|
||||
|
||||
/**
|
||||
* Decode and read the request body to a single object.
|
||||
*
|
||||
* @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 decoded stream of elements
|
||||
*/
|
||||
Mono<T> readMono(ResolvableType actualType, ResolvableType elementType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints);
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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.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.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.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> {
|
||||
|
||||
/**
|
||||
* Encode and write the given object stream to the response.
|
||||
*
|
||||
* @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 actualType,
|
||||
ResolvableType elementType, MediaType mediaType, ServerHttpRequest request,
|
||||
ServerHttpResponse response, Map<String, Object> hints);
|
||||
|
||||
}
|
||||
@@ -37,14 +37,14 @@ import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
|
||||
/**
|
||||
* {@code ServerHttpMessageWriter} for {@code "text/event-stream"} responses.
|
||||
* {@code HttpMessageWriter} for {@code "text/event-stream"} responses.
|
||||
*
|
||||
* @author Sebastien Deleuze
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ServerSentEventHttpMessageWriter implements ServerHttpMessageWriter<Object> {
|
||||
public class ServerSentEventHttpMessageWriter implements HttpMessageWriter<Object> {
|
||||
|
||||
private static final List<MediaType> WRITABLE_MEDIA_TYPES =
|
||||
Collections.singletonList(MediaType.TEXT_EVENT_STREAM);
|
||||
@@ -172,8 +172,8 @@ public class ServerSentEventHttpMessageWriter implements ServerHttpMessageWriter
|
||||
private Map<String, Object> getEncodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||
MediaType mediaType, ServerHttpRequest request, ServerHttpResponse response) {
|
||||
|
||||
if (this.encoder instanceof HttpEncoder) {
|
||||
HttpEncoder<?> httpEncoder = (HttpEncoder<?>) this.encoder;
|
||||
if (this.encoder instanceof HttpMessageEncoder) {
|
||||
HttpMessageEncoder<?> httpEncoder = (HttpMessageEncoder<?>) this.encoder;
|
||||
return httpEncoder.getEncodeHints(actualType, elementType, mediaType, request, response);
|
||||
}
|
||||
return Collections.emptyMap();
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.http.codec.HttpDecoder;
|
||||
import org.springframework.http.codec.HttpMessageDecoder;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
@@ -48,7 +48,7 @@ import org.springframework.util.MimeType;
|
||||
* @since 5.0
|
||||
* @see Jackson2JsonEncoder
|
||||
*/
|
||||
public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpDecoder<Object> {
|
||||
public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpMessageDecoder<Object> {
|
||||
|
||||
private final JsonObjectDecoder fluxDecoder = new JsonObjectDecoder(true);
|
||||
|
||||
@@ -120,7 +120,7 @@ public class Jackson2JsonDecoder extends Jackson2CodecSupport implements HttpDec
|
||||
}
|
||||
|
||||
|
||||
// HttpDecoder...
|
||||
// HttpMessageDecoder...
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getDecodeHints(ResolvableType actualType, ResolvableType elementType,
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.springframework.core.codec.CodecException;
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.HttpEncoder;
|
||||
import org.springframework.http.codec.HttpMessageEncoder;
|
||||
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
@@ -59,7 +59,7 @@ import org.springframework.util.MimeType;
|
||||
* @since 5.0
|
||||
* @see Jackson2JsonDecoder
|
||||
*/
|
||||
public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpEncoder<Object> {
|
||||
public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpMessageEncoder<Object> {
|
||||
|
||||
private final List<MediaType> streamingMediaTypes = new ArrayList<>(1);
|
||||
|
||||
@@ -89,7 +89,7 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpEnc
|
||||
* automatically vs at the end of the stream.
|
||||
* <p>By default this is set to {@link MediaType#APPLICATION_STREAM_JSON}.
|
||||
* @param mediaTypes one or more media types to add to the list
|
||||
* @see HttpEncoder#getStreamingMediaTypes()
|
||||
* @see HttpMessageEncoder#getStreamingMediaTypes()
|
||||
*/
|
||||
public void setStreamingMediaTypes(List<MediaType> mediaTypes) {
|
||||
this.streamingMediaTypes.clear();
|
||||
@@ -169,7 +169,7 @@ public class Jackson2JsonEncoder extends Jackson2CodecSupport implements HttpEnc
|
||||
}
|
||||
|
||||
|
||||
// HttpEncoder...
|
||||
// HttpMessageEncoder...
|
||||
|
||||
@Override
|
||||
public List<MediaType> getStreamingMediaTypes() {
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.codec.ByteArrayDecoder;
|
||||
import org.springframework.core.codec.ByteArrayEncoder;
|
||||
import org.springframework.core.codec.ByteBufferDecoder;
|
||||
import org.springframework.core.codec.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
import org.springframework.core.codec.DataBufferDecoder;
|
||||
import org.springframework.core.codec.DataBufferEncoder;
|
||||
import org.springframework.core.codec.Decoder;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.ResourceDecoder;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
|
||||
import org.springframework.util.MimeTypeUtils;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.core.ResolvableType.forClass;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ServerCodecConfigurer}.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ServerCodecConfigurerTests {
|
||||
|
||||
private final ServerCodecConfigurer configurer = new ServerCodecConfigurer();
|
||||
|
||||
private final AtomicInteger index = new AtomicInteger(0);
|
||||
|
||||
|
||||
@Test
|
||||
public void defaultReaders() throws Exception {
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
assertEquals(8, readers.size());
|
||||
assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ByteBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertStringDecoder(getNextDecoder(readers), true);
|
||||
assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertStringDecoder(getNextDecoder(readers), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultWriters() throws Exception {
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
|
||||
assertEquals(9, writers.size());
|
||||
assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
|
||||
assertStringEncoder(getNextEncoder(writers), true);
|
||||
assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertSseWriter(writers);
|
||||
assertStringEncoder(getNextEncoder(writers), false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultAndCustomReaders() throws Exception {
|
||||
|
||||
Decoder<?> customDecoder1 = mock(Decoder.class);
|
||||
Decoder<?> customDecoder2 = mock(Decoder.class);
|
||||
|
||||
when(customDecoder1.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customDecoder2.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
HttpMessageReader<?> customReader1 = mock(HttpMessageReader.class);
|
||||
HttpMessageReader<?> customReader2 = mock(HttpMessageReader.class);
|
||||
|
||||
when(customReader1.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customReader2.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
this.configurer.customCodec().decoder(customDecoder1);
|
||||
this.configurer.customCodec().decoder(customDecoder2);
|
||||
|
||||
this.configurer.customCodec().reader(customReader1);
|
||||
this.configurer.customCodec().reader(customReader2);
|
||||
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
|
||||
assertEquals(12, readers.size());
|
||||
assertEquals(ByteArrayDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ByteBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(DataBufferDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(ResourceDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(StringDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertSame(customDecoder1, getNextDecoder(readers));
|
||||
assertSame(customReader1, readers.get(this.index.getAndIncrement()));
|
||||
assertEquals(Jaxb2XmlDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertEquals(Jackson2JsonDecoder.class, getNextDecoder(readers).getClass());
|
||||
assertSame(customDecoder2, getNextDecoder(readers));
|
||||
assertSame(customReader2, readers.get(this.index.getAndIncrement()));
|
||||
assertEquals(StringDecoder.class, getNextDecoder(readers).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultAndCustomWriters() throws Exception {
|
||||
|
||||
Encoder<?> customEncoder1 = mock(Encoder.class);
|
||||
Encoder<?> customEncoder2 = mock(Encoder.class);
|
||||
|
||||
when(customEncoder1.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customEncoder2.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
HttpMessageWriter<?> customWriter1 = mock(HttpMessageWriter.class);
|
||||
HttpMessageWriter<?> customWriter2 = mock(HttpMessageWriter.class);
|
||||
|
||||
when(customWriter1.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customWriter2.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
this.configurer.customCodec().encoder(customEncoder1);
|
||||
this.configurer.customCodec().encoder(customEncoder2);
|
||||
|
||||
this.configurer.customCodec().writer(customWriter1);
|
||||
this.configurer.customCodec().writer(customWriter2);
|
||||
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
|
||||
|
||||
assertEquals(13, writers.size());
|
||||
assertEquals(ByteArrayEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(ByteBufferEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(DataBufferEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(ResourceHttpMessageWriter.class, writers.get(index.getAndIncrement()).getClass());
|
||||
assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertSame(customEncoder1, getNextEncoder(writers));
|
||||
assertSame(customWriter1, writers.get(this.index.getAndIncrement()));
|
||||
assertEquals(Jaxb2XmlEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(Jackson2JsonEncoder.class, getNextEncoder(writers).getClass());
|
||||
assertEquals(ServerSentEventHttpMessageWriter.class, writers.get(this.index.getAndIncrement()).getClass());
|
||||
assertSame(customEncoder2, getNextEncoder(writers));
|
||||
assertSame(customWriter2, writers.get(this.index.getAndIncrement()));
|
||||
assertEquals(CharSequenceEncoder.class, getNextEncoder(writers).getClass());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultsOffCustomReaders() throws Exception {
|
||||
|
||||
Decoder<?> customDecoder1 = mock(Decoder.class);
|
||||
Decoder<?> customDecoder2 = mock(Decoder.class);
|
||||
|
||||
when(customDecoder1.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customDecoder2.canDecode(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
HttpMessageReader<?> customReader1 = mock(HttpMessageReader.class);
|
||||
HttpMessageReader<?> customReader2 = mock(HttpMessageReader.class);
|
||||
|
||||
when(customReader1.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customReader2.canRead(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
this.configurer.customCodec().decoder(customDecoder1);
|
||||
this.configurer.customCodec().decoder(customDecoder2);
|
||||
|
||||
this.configurer.customCodec().reader(customReader1);
|
||||
this.configurer.customCodec().reader(customReader2);
|
||||
|
||||
this.configurer.registerDefaults(false);
|
||||
|
||||
List<HttpMessageReader<?>> readers = this.configurer.getReaders();
|
||||
|
||||
assertEquals(4, readers.size());
|
||||
assertSame(customDecoder1, getNextDecoder(readers));
|
||||
assertSame(customReader1, readers.get(this.index.getAndIncrement()));
|
||||
assertSame(customDecoder2, getNextDecoder(readers));
|
||||
assertSame(customReader2, readers.get(this.index.getAndIncrement()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void defaultsOffWithCustomWriters() throws Exception {
|
||||
|
||||
Encoder<?> customEncoder1 = mock(Encoder.class);
|
||||
Encoder<?> customEncoder2 = mock(Encoder.class);
|
||||
|
||||
when(customEncoder1.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customEncoder2.canEncode(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
HttpMessageWriter<?> customWriter1 = mock(HttpMessageWriter.class);
|
||||
HttpMessageWriter<?> customWriter2 = mock(HttpMessageWriter.class);
|
||||
|
||||
when(customWriter1.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(false);
|
||||
when(customWriter2.canWrite(ResolvableType.forClass(Object.class), null)).thenReturn(true);
|
||||
|
||||
this.configurer.customCodec().encoder(customEncoder1);
|
||||
this.configurer.customCodec().encoder(customEncoder2);
|
||||
|
||||
this.configurer.customCodec().writer(customWriter1);
|
||||
this.configurer.customCodec().writer(customWriter2);
|
||||
|
||||
this.configurer.registerDefaults(false);
|
||||
|
||||
List<HttpMessageWriter<?>> writers = this.configurer.getWriters();
|
||||
|
||||
assertEquals(4, writers.size());
|
||||
assertSame(customEncoder1, getNextEncoder(writers));
|
||||
assertSame(customWriter1, writers.get(this.index.getAndIncrement()));
|
||||
assertSame(customEncoder2, getNextEncoder(writers));
|
||||
assertSame(customWriter2, writers.get(this.index.getAndIncrement()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jackson2DecoderOverride() throws Exception {
|
||||
|
||||
Jackson2JsonDecoder decoder = new Jackson2JsonDecoder();
|
||||
this.configurer.defaultCodec().jackson2Decoder(decoder);
|
||||
|
||||
assertSame(decoder, this.configurer.getReaders().stream()
|
||||
.filter(writer -> writer instanceof DecoderHttpMessageReader)
|
||||
.map(writer -> ((DecoderHttpMessageReader<?>) writer).getDecoder())
|
||||
.filter(e -> Jackson2JsonDecoder.class.equals(e.getClass()))
|
||||
.findFirst()
|
||||
.filter(e -> e == decoder).orElse(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jackson2EncoderOverride() throws Exception {
|
||||
|
||||
Jackson2JsonEncoder encoder = new Jackson2JsonEncoder();
|
||||
this.configurer.defaultCodec().jackson2Encoder(encoder);
|
||||
|
||||
assertSame(encoder, this.configurer.getWriters().stream()
|
||||
.filter(writer -> writer instanceof EncoderHttpMessageWriter)
|
||||
.map(writer -> ((EncoderHttpMessageWriter<?>) writer).getEncoder())
|
||||
.filter(e -> Jackson2JsonEncoder.class.equals(e.getClass()))
|
||||
.findFirst()
|
||||
.filter(e -> e == encoder).orElse(null));
|
||||
|
||||
assertSame(encoder, this.configurer.getWriters().stream()
|
||||
.filter(writer -> ServerSentEventHttpMessageWriter.class.equals(writer.getClass()))
|
||||
.map(writer -> (ServerSentEventHttpMessageWriter) writer)
|
||||
.findFirst()
|
||||
.map(ServerSentEventHttpMessageWriter::getEncoder)
|
||||
.filter(e -> e == encoder).orElse(null));
|
||||
}
|
||||
|
||||
|
||||
private Decoder<?> getNextDecoder(List<HttpMessageReader<?>> readers) {
|
||||
HttpMessageReader<?> reader = readers.get(this.index.getAndIncrement());
|
||||
assertEquals(DecoderHttpMessageReader.class, reader.getClass());
|
||||
return ((DecoderHttpMessageReader) reader).getDecoder();
|
||||
}
|
||||
|
||||
private Encoder<?> getNextEncoder(List<HttpMessageWriter<?>> writers) {
|
||||
HttpMessageWriter<?> writer = writers.get(this.index.getAndIncrement());
|
||||
assertEquals(EncoderHttpMessageWriter.class, writer.getClass());
|
||||
return ((EncoderHttpMessageWriter) writer).getEncoder();
|
||||
}
|
||||
|
||||
private void assertStringDecoder(Decoder<?> decoder, boolean textOnly) {
|
||||
assertEquals(StringDecoder.class, decoder.getClass());
|
||||
assertTrue(decoder.canDecode(forClass(String.class), MimeTypeUtils.TEXT_PLAIN));
|
||||
assertEquals(!textOnly, decoder.canDecode(forClass(String.class), MediaType.TEXT_EVENT_STREAM));
|
||||
}
|
||||
|
||||
private void assertStringEncoder(Encoder<?> encoder, boolean textOnly) {
|
||||
assertEquals(CharSequenceEncoder.class, encoder.getClass());
|
||||
assertTrue(encoder.canEncode(forClass(String.class), MimeTypeUtils.TEXT_PLAIN));
|
||||
assertEquals(!textOnly, encoder.canEncode(forClass(String.class), MediaType.TEXT_EVENT_STREAM));
|
||||
}
|
||||
|
||||
private void assertSseWriter(List<HttpMessageWriter<?>> writers) {
|
||||
HttpMessageWriter<?> writer = writers.get(this.index.getAndIncrement());
|
||||
assertEquals(ServerSentEventHttpMessageWriter.class, writer.getClass());
|
||||
Encoder<?> encoder = ((ServerSentEventHttpMessageWriter) writer).getEncoder();
|
||||
assertNotNull(encoder);
|
||||
assertEquals(Jackson2JsonEncoder.class, encoder.getClass());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,8 +21,7 @@ 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
@@ -76,13 +75,8 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
|
||||
this.configurers.configureMessageReaders(messageReaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extendMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
|
||||
this.configurers.extendMessageReaders(messageReaders);
|
||||
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
|
||||
this.configurers.configureHttpMessageCodecs(configurer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,16 +94,6 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport
|
||||
return this.configurers.getMessageCodesResolver().orElse(super.getMessageCodesResolver());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
|
||||
this.configurers.configureMessageWriters(messageWriters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extendMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
|
||||
this.configurers.extendMessageWriters(messageWriters);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureViewResolvers(ViewResolverRegistry registry) {
|
||||
this.configurers.configureViewResolvers(registry);
|
||||
|
||||
@@ -30,32 +30,13 @@ import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.ReactiveAdapterRegistry;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.codec.ByteArrayDecoder;
|
||||
import org.springframework.core.codec.ByteArrayEncoder;
|
||||
import org.springframework.core.codec.ByteBufferDecoder;
|
||||
import org.springframework.core.codec.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
import org.springframework.core.codec.DataBufferDecoder;
|
||||
import org.springframework.core.codec.DataBufferEncoder;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.ResourceDecoder;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.format.Formatter;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
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.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;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
@@ -104,9 +85,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
||||
|
||||
private PathMatchConfigurer pathMatchConfigurer;
|
||||
|
||||
private List<ServerHttpMessageReader<?>> messageReaders;
|
||||
|
||||
private List<ServerHttpMessageWriter<?>> messageWriters;
|
||||
private ServerCodecConfigurer messageCodecsConfigurer;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@@ -267,7 +246,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
||||
@Bean
|
||||
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
|
||||
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
|
||||
adapter.setMessageReaders(getMessageReaders());
|
||||
adapter.setMessageReaders(getMessageCodecsConfigurer().getReaders());
|
||||
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
|
||||
adapter.setReactiveAdapterRegistry(webFluxAdapterRegistry());
|
||||
|
||||
@@ -294,58 +273,22 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method to access message readers to use for decoding
|
||||
* controller method arguments with.
|
||||
* <p>Use {@link #configureMessageReaders} to configure the list or
|
||||
* {@link #extendMessageReaders} to add in addition to the default ones.
|
||||
* Main method to access the configurer for HTTP message readers and writers.
|
||||
* <p>Use {@link #configureHttpMessageCodecs(ServerCodecConfigurer)} to
|
||||
* configure the readers and writers.
|
||||
*/
|
||||
protected final List<ServerHttpMessageReader<?>> getMessageReaders() {
|
||||
if (this.messageReaders == null) {
|
||||
this.messageReaders = new ArrayList<>();
|
||||
configureMessageReaders(this.messageReaders);
|
||||
if (this.messageReaders.isEmpty()) {
|
||||
addDefaultHttpMessageReaders(this.messageReaders);
|
||||
}
|
||||
extendMessageReaders(this.messageReaders);
|
||||
protected final ServerCodecConfigurer getMessageCodecsConfigurer() {
|
||||
if (this.messageCodecsConfigurer == null) {
|
||||
this.messageCodecsConfigurer = new ServerCodecConfigurer();
|
||||
configureHttpMessageCodecs(this.getMessageCodecsConfigurer());
|
||||
}
|
||||
return this.messageReaders;
|
||||
return this.messageCodecsConfigurer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to configure the message readers to use for decoding
|
||||
* controller method arguments.
|
||||
* <p>If no message readres are specified, default will be added via
|
||||
* {@link #addDefaultHttpMessageReaders}.
|
||||
* @param messageReaders a list to add message readers to, initially an empty
|
||||
* Override to configure the HTTP message readers and writers to use.
|
||||
*/
|
||||
protected void configureMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default converters that sub-classes can call from
|
||||
* {@link #configureMessageReaders(List)} for {@code byte[]},
|
||||
* {@code ByteBuffer}, {@code String}, {@code Resource}, JAXB2, and Jackson
|
||||
* (if present on the classpath).
|
||||
*/
|
||||
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()));
|
||||
readers.add(new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes(true)));
|
||||
readers.add(new DecoderHttpMessageReader<>(new ResourceDecoder()));
|
||||
if (jaxb2Present) {
|
||||
readers.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder()));
|
||||
}
|
||||
if (jackson2Present) {
|
||||
readers.add(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<ServerHttpMessageReader<?>> messageReaders) {
|
||||
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -435,76 +378,14 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
|
||||
|
||||
@Bean
|
||||
public ResponseEntityResultHandler responseEntityResultHandler() {
|
||||
return new ResponseEntityResultHandler(
|
||||
getMessageWriters(), webFluxContentTypeResolver(), webFluxAdapterRegistry());
|
||||
return new ResponseEntityResultHandler(getMessageCodecsConfigurer().getWriters(),
|
||||
webFluxContentTypeResolver(), webFluxAdapterRegistry());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ResponseBodyResultHandler responseBodyResultHandler() {
|
||||
return new ResponseBodyResultHandler(
|
||||
getMessageWriters(), webFluxContentTypeResolver(), webFluxAdapterRegistry());
|
||||
}
|
||||
|
||||
/**
|
||||
* Main method to access message writers to use for encoding return values.
|
||||
* <p>Use {@link #configureMessageWriters(List)} to configure the list or
|
||||
* {@link #extendMessageWriters(List)} to add in addition to the default ones.
|
||||
*/
|
||||
protected final List<ServerHttpMessageWriter<?>> getMessageWriters() {
|
||||
if (this.messageWriters == null) {
|
||||
this.messageWriters = new ArrayList<>();
|
||||
configureMessageWriters(this.messageWriters);
|
||||
if (this.messageWriters.isEmpty()) {
|
||||
addDefaultHttpMessageWriters(this.messageWriters);
|
||||
}
|
||||
extendMessageWriters(this.messageWriters);
|
||||
}
|
||||
return this.messageWriters;
|
||||
}
|
||||
/**
|
||||
* Override to configure the message writers to use for encoding
|
||||
* return values.
|
||||
* <p>If no message readers are specified, default will be added via
|
||||
* {@link #addDefaultHttpMessageWriters}.
|
||||
* @param messageWriters a list to add message writers to, initially an empty
|
||||
*/
|
||||
protected void configureMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds default converters that sub-classes can call from
|
||||
* {@link #configureMessageWriters(List)}.
|
||||
*/
|
||||
protected final void addDefaultHttpMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(new ByteArrayEncoder()));
|
||||
writers.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
|
||||
writers.add(new EncoderHttpMessageWriter<>(new DataBufferEncoder()));
|
||||
writers.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
|
||||
writers.add(new ResourceHttpMessageWriter());
|
||||
if (jaxb2Present) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
|
||||
}
|
||||
if (jackson2Present) {
|
||||
writers.add(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
|
||||
}
|
||||
writers.add(new ServerSentEventHttpMessageWriter(getSseEncoder()));
|
||||
writers.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
|
||||
}
|
||||
|
||||
private Encoder<?> getSseEncoder() {
|
||||
if (jackson2Present) {
|
||||
return new Jackson2JsonEncoder();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<ServerHttpMessageWriter<?>> messageWriters) {
|
||||
return new ResponseBodyResultHandler(getMessageCodecsConfigurer().getWriters(),
|
||||
webFluxContentTypeResolver(), webFluxAdapterRegistry());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -22,8 +22,7 @@ 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
|
||||
@@ -89,22 +88,10 @@ public interface WebFluxConfigurer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the message readers to use for decoding the request body where
|
||||
* {@code @RequestBody} and {@code HttpEntity} controller method arguments
|
||||
* are used. If none are specified, default ones are added based on
|
||||
* {@link WebFluxConfigurationSupport#addDefaultHttpMessageReaders}.
|
||||
* <p>See {@link #extendMessageReaders(List)} for adding readers
|
||||
* in addition to the default ones.
|
||||
* @param readers an empty list to add message readers to
|
||||
* Configure custom HTTP message readers and writers or override built-in ones.
|
||||
* @param configurer the configurer to use
|
||||
*/
|
||||
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<ServerHttpMessageReader<?>> readers) {
|
||||
default void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,25 +119,6 @@ public interface WebFluxConfigurer {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the message writers to use to encode the response body based on
|
||||
* the return values of {@code @ResponseBody}, and {@code ResponseEntity}
|
||||
* controller methods. If none are specified, default ones are added based on
|
||||
* {@link WebFluxConfigurationSupport#addDefaultHttpMessageWriters(List)}.
|
||||
* <p>See {@link #extendMessageWriters(List)} for adding writers
|
||||
* in addition to the default ones.
|
||||
* @param writers a empty list to add message writers to
|
||||
*/
|
||||
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<ServerHttpMessageWriter<?>> writers) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure view resolution for processing the return values of controller
|
||||
* methods that rely on resolving a
|
||||
|
||||
@@ -23,8 +23,7 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.http.codec.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
import org.springframework.validation.Validator;
|
||||
@@ -52,42 +51,37 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
|
||||
|
||||
@Override
|
||||
public void configureContentTypeResolver(RequestedContentTypeResolverBuilder builder) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.configureContentTypeResolver(builder));
|
||||
this.delegates.forEach(delegate -> delegate.configureContentTypeResolver(builder));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.addCorsMappings(registry));
|
||||
this.delegates.forEach(delegate -> delegate.addCorsMappings(registry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configurePathMatching(PathMatchConfigurer configurer) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.configurePathMatching(configurer));
|
||||
this.delegates.forEach(delegate -> delegate.configurePathMatching(configurer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.addResourceHandlers(registry));
|
||||
this.delegates.forEach(delegate -> delegate.addResourceHandlers(registry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.addArgumentResolvers(resolvers));
|
||||
this.delegates.forEach(delegate -> delegate.addArgumentResolvers(resolvers));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageReaders(List<ServerHttpMessageReader<?>> readers) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.configureMessageReaders(readers));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendMessageReaders(List<ServerHttpMessageReader<?>> readers) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.extendMessageReaders(readers));
|
||||
public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
|
||||
this.delegates.forEach(delegate -> delegate.configureHttpMessageCodecs(configurer));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFormatters(FormatterRegistry registry) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.addFormatters(registry));
|
||||
this.delegates.forEach(delegate -> delegate.addFormatters(registry));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,19 +94,9 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
|
||||
return createSingleBean(WebFluxConfigurer::getMessageCodesResolver, MessageCodesResolver.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.configureMessageWriters(writers));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void extendMessageWriters(List<ServerHttpMessageWriter<?>> writers) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.extendMessageWriters(writers));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureViewResolvers(ViewResolverRegistry registry) {
|
||||
this.delegates.stream().forEach(delegate -> delegate.configureViewResolvers(registry));
|
||||
this.delegates.forEach(delegate -> delegate.configureViewResolvers(registry));
|
||||
}
|
||||
|
||||
private <T> Optional<T> createSingleBean(Function<WebFluxConfigurer, Optional<T>> factory,
|
||||
|
||||
@@ -26,26 +26,10 @@ import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.codec.ByteArrayDecoder;
|
||||
import org.springframework.core.codec.ByteArrayEncoder;
|
||||
import org.springframework.core.codec.ByteBufferDecoder;
|
||||
import org.springframework.core.codec.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
import org.springframework.core.codec.Encoder;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.http.codec.DecoderHttpMessageReader;
|
||||
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.ResourceHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerSentEventHttpMessageWriter;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
|
||||
/**
|
||||
@@ -61,16 +45,6 @@ class DefaultHandlerStrategiesBuilder implements HandlerStrategies.Builder {
|
||||
.map(Locale.LanguageRange::getRange)
|
||||
.map(Locale::forLanguageTag).findFirst();
|
||||
|
||||
private static final boolean jackson2Present =
|
||||
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
|
||||
DefaultHandlerStrategiesBuilder.class.getClassLoader()) &&
|
||||
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",
|
||||
DefaultHandlerStrategiesBuilder.class.getClassLoader());
|
||||
|
||||
private static final boolean jaxb2Present =
|
||||
ClassUtils.isPresent("javax.xml.bind.Binder",
|
||||
DefaultHandlerStrategiesBuilder.class.getClassLoader());
|
||||
|
||||
|
||||
private final List<HttpMessageReader<?>> messageReaders = new ArrayList<>();
|
||||
|
||||
@@ -82,40 +56,12 @@ class DefaultHandlerStrategiesBuilder implements HandlerStrategies.Builder {
|
||||
|
||||
|
||||
public void defaultConfiguration() {
|
||||
messageReader(new DecoderHttpMessageReader<>(new ByteArrayDecoder()));
|
||||
messageReader(new DecoderHttpMessageReader<>(new ByteBufferDecoder()));
|
||||
messageReader(new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes(true)));
|
||||
messageReader(new FormHttpMessageReader());
|
||||
|
||||
messageWriter(new EncoderHttpMessageWriter<>(new ByteArrayEncoder()));
|
||||
messageWriter(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
|
||||
messageWriter(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
|
||||
messageWriter(new ResourceHttpMessageWriter());
|
||||
|
||||
if (jaxb2Present) {
|
||||
messageReader(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder()));
|
||||
messageWriter(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
|
||||
}
|
||||
if (jackson2Present) {
|
||||
messageReader(new DecoderHttpMessageReader<>(new Jackson2JsonDecoder()));
|
||||
messageWriter(new EncoderHttpMessageWriter<>(new Jackson2JsonEncoder()));
|
||||
}
|
||||
|
||||
messageWriter(new ServerSentEventHttpMessageWriter(getSseEncoder()));
|
||||
messageWriter(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
|
||||
|
||||
ServerCodecConfigurer configurer = new ServerCodecConfigurer();
|
||||
configurer.getReaders().forEach(this::messageReader);
|
||||
configurer.getWriters().forEach(this::messageWriter);
|
||||
localeResolver(DEFAULT_LOCALE_RESOLVER);
|
||||
}
|
||||
|
||||
private Encoder<?> getSseEncoder() {
|
||||
if (jackson2Present) {
|
||||
return new Jackson2JsonEncoder();
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void applicationContext(ApplicationContext applicationContext) {
|
||||
applicationContext.getBeansOfType(HttpMessageReader.class).values().forEach(this::messageReader);
|
||||
applicationContext.getBeansOfType(HttpMessageWriter.class).values().forEach(this::messageWriter);
|
||||
|
||||
@@ -32,7 +32,7 @@ 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -48,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 ServerHttpMessageReader}.
|
||||
* by reading the request body with an {@link HttpMessageReader}.
|
||||
*
|
||||
* <p>Applies validation if the method argument is annotated with
|
||||
* {@code @javax.validation.Valid} or
|
||||
@@ -60,16 +60,16 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||
*/
|
||||
public abstract class AbstractMessageReaderArgumentResolver extends HandlerMethodArgumentResolverSupport {
|
||||
|
||||
private final List<ServerHttpMessageReader<?>> messageReaders;
|
||||
private final List<HttpMessageReader<?>> messageReaders;
|
||||
|
||||
private final List<MediaType> supportedMediaTypes;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor with {@link ServerHttpMessageReader}'s and a {@link Validator}.
|
||||
* Constructor with {@link HttpMessageReader}'s and a {@link Validator}.
|
||||
* @param readers readers to convert from the request body
|
||||
*/
|
||||
protected AbstractMessageReaderArgumentResolver(List<ServerHttpMessageReader<?>> readers) {
|
||||
protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> readers) {
|
||||
this(readers, new ReactiveAdapterRegistry());
|
||||
}
|
||||
|
||||
@@ -78,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<ServerHttpMessageReader<?>> messageReaders,
|
||||
protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> messageReaders,
|
||||
ReactiveAdapterRegistry adapterRegistry) {
|
||||
|
||||
super(adapterRegistry);
|
||||
@@ -94,7 +94,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
|
||||
/**
|
||||
* Return the configured message converters.
|
||||
*/
|
||||
public List<ServerHttpMessageReader<?>> getMessageReaders() {
|
||||
public List<HttpMessageReader<?>> getMessageReaders() {
|
||||
return this.messageReaders;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public abstract class AbstractMessageReaderArgumentResolver extends HandlerMetho
|
||||
mediaType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
}
|
||||
|
||||
for (ServerHttpMessageReader<?> reader : getMessageReaders()) {
|
||||
for (HttpMessageReader<?> reader : getMessageReaders()) {
|
||||
if (reader.canRead(elementType, mediaType)) {
|
||||
Map<String, Object> readHints = Collections.emptyMap();
|
||||
if (adapter != null && adapter.isMultiValue()) {
|
||||
|
||||
@@ -27,7 +27,7 @@ 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.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -38,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 ServerHttpMessageWriter}.
|
||||
* to the response with {@link HttpMessageWriter}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public abstract class AbstractMessageWriterResultHandler extends HandlerResultHandlerSupport {
|
||||
|
||||
private final List<ServerHttpMessageWriter<?>> messageWriters;
|
||||
private final List<HttpMessageWriter<?>> messageWriters;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor with {@link ServerHttpMessageWriter}s and a
|
||||
* Constructor with {@link HttpMessageWriter}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<ServerHttpMessageWriter<?>> messageWriters,
|
||||
protected AbstractMessageWriterResultHandler(List<HttpMessageWriter<?>> messageWriters,
|
||||
RequestedContentTypeResolver contentTypeResolver) {
|
||||
|
||||
super(contentTypeResolver);
|
||||
@@ -71,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<ServerHttpMessageWriter<?>> messageWriters,
|
||||
protected AbstractMessageWriterResultHandler(List<HttpMessageWriter<?>> messageWriters,
|
||||
RequestedContentTypeResolver contentTypeResolver,
|
||||
ReactiveAdapterRegistry adapterRegistry) {
|
||||
|
||||
@@ -84,7 +84,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
|
||||
/**
|
||||
* Return the configured message converters.
|
||||
*/
|
||||
public List<ServerHttpMessageWriter<?>> getMessageWriters() {
|
||||
public List<HttpMessageWriter<?>> getMessageWriters() {
|
||||
return this.messageWriters;
|
||||
}
|
||||
|
||||
@@ -115,7 +115,7 @@ public abstract class AbstractMessageWriterResultHandler extends HandlerResultHa
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
MediaType bestMediaType = selectMediaType(exchange, () -> getProducibleMediaTypes(elementType));
|
||||
if (bestMediaType != null) {
|
||||
for (ServerHttpMessageWriter<?> writer : getMessageWriters()) {
|
||||
for (HttpMessageWriter<?> 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
|
||||
@@ -40,7 +40,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
*/
|
||||
public class HttpEntityArgumentResolver extends AbstractMessageReaderArgumentResolver {
|
||||
|
||||
public HttpEntityArgumentResolver(List<ServerHttpMessageReader<?>> readers,
|
||||
public HttpEntityArgumentResolver(List<HttpMessageReader<?>> 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.reactive.BindingContext;
|
||||
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
|
||||
@@ -45,7 +45,7 @@ import org.springframework.web.server.ServerWebInputException;
|
||||
*/
|
||||
public class RequestBodyArgumentResolver extends AbstractMessageReaderArgumentResolver {
|
||||
|
||||
public RequestBodyArgumentResolver(List<ServerHttpMessageReader<?>> readers,
|
||||
public RequestBodyArgumentResolver(List<HttpMessageReader<?>> readers,
|
||||
ReactiveAdapterRegistry registry) {
|
||||
|
||||
super(readers, registry);
|
||||
|
||||
@@ -42,9 +42,11 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.codec.ByteArrayDecoder;
|
||||
import org.springframework.core.codec.ByteBufferDecoder;
|
||||
import org.springframework.core.codec.DataBufferDecoder;
|
||||
import org.springframework.core.codec.ResourceDecoder;
|
||||
import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.http.codec.DecoderHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
@@ -76,7 +78,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
|
||||
private static final Log logger = LogFactory.getLog(RequestMappingHandlerAdapter.class);
|
||||
|
||||
|
||||
private final List<ServerHttpMessageReader<?>> messageReaders = new ArrayList<>(10);
|
||||
private final List<HttpMessageReader<?>> messageReaders = new ArrayList<>(10);
|
||||
|
||||
private WebBindingInitializer webBindingInitializer;
|
||||
|
||||
@@ -114,26 +116,30 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
|
||||
|
||||
|
||||
public RequestMappingHandlerAdapter() {
|
||||
// TODO: improve with better (shared) defaults
|
||||
this.messageReaders.add(new DecoderHttpMessageReader<>(new ByteArrayDecoder()));
|
||||
this.messageReaders.add(new DecoderHttpMessageReader<>(new ByteBufferDecoder()));
|
||||
this.messageReaders.add(new DecoderHttpMessageReader<>(new DataBufferDecoder()));
|
||||
this.messageReaders.add(new DecoderHttpMessageReader<>(new ResourceDecoder()));
|
||||
this.messageReaders.add(new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes(true)));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure message readers to de-serialize the request body with.
|
||||
* Configure HTTP message readers to de-serialize the request body with.
|
||||
* <p>By default only basic data types such as bytes and text are registered.
|
||||
* Consider using {@link ServerCodecConfigurer} to configure a richer list
|
||||
* including JSON encoding .
|
||||
* @see ServerCodecConfigurer
|
||||
*/
|
||||
public void setMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
|
||||
public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
|
||||
this.messageReaders.clear();
|
||||
this.messageReaders.addAll(messageReaders);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the configured message readers.
|
||||
* Return the configured HTTP message readers.
|
||||
*/
|
||||
public List<ServerHttpMessageReader<?>> getMessageReaders() {
|
||||
public List<HttpMessageReader<?>> 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.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
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 ServerHttpMessageWriter}.
|
||||
* an {@link HttpMessageWriter}.
|
||||
*
|
||||
* <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<ServerHttpMessageWriter<?>> writers,
|
||||
public ResponseBodyResultHandler(List<HttpMessageWriter<?>> 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<ServerHttpMessageWriter<?>> writers,
|
||||
public ResponseBodyResultHandler(List<HttpMessageWriter<?>> 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.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
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<ServerHttpMessageWriter<?>> writers,
|
||||
public ResponseEntityResultHandler(List<HttpMessageWriter<?>> 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<ServerHttpMessageWriter<?>> writers,
|
||||
public ResponseEntityResultHandler(List<HttpMessageWriter<?>> 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
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<ServerHttpMessageReader<?>>> readers;
|
||||
private ArgumentCaptor<ServerCodecConfigurer> codecsConfigurer;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<List<ServerHttpMessageWriter<?>>> writers;
|
||||
private ArgumentCaptor<List<HttpMessageWriter<?>>> writers;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<FormatterRegistry> formatterRegistry;
|
||||
@@ -96,15 +96,14 @@ public class DelegatingWebFluxConfigurationTests {
|
||||
ConversionService initializerConversionService = initializer.getConversionService();
|
||||
assertTrue(initializer.getValidator() instanceof LocalValidatorFactoryBean);
|
||||
|
||||
verify(webFluxConfigurer).configureMessageReaders(readers.capture());
|
||||
verify(webFluxConfigurer).extendMessageReaders(readers.capture());
|
||||
verify(webFluxConfigurer).configureHttpMessageCodecs(codecsConfigurer.capture());
|
||||
verify(webFluxConfigurer).getValidator();
|
||||
verify(webFluxConfigurer).getMessageCodesResolver();
|
||||
verify(webFluxConfigurer).addFormatters(formatterRegistry.capture());
|
||||
verify(webFluxConfigurer).addArgumentResolvers(any());
|
||||
|
||||
assertSame(formatterRegistry.getValue(), initializerConversionService);
|
||||
assertEquals(7, readers.getValue().size());
|
||||
assertEquals(8, codecsConfigurer.getValue().getReaders().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -126,8 +125,7 @@ public class DelegatingWebFluxConfigurationTests {
|
||||
delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer));
|
||||
delegatingConfig.responseBodyResultHandler();
|
||||
|
||||
verify(webFluxConfigurer).configureMessageWriters(writers.capture());
|
||||
verify(webFluxConfigurer).extendMessageWriters(writers.capture());
|
||||
verify(webFluxConfigurer).configureHttpMessageCodecs(codecsConfigurer.capture());
|
||||
verify(webFluxConfigurer).configureContentTypeResolver(any(RequestedContentTypeResolverBuilder.class));
|
||||
}
|
||||
|
||||
|
||||
@@ -34,10 +34,9 @@ import org.springframework.core.codec.StringDecoder;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerCodecConfigurer;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlDecoder;
|
||||
import org.springframework.http.codec.xml.Jaxb2XmlEncoder;
|
||||
@@ -127,8 +126,8 @@ public class WebFluxConfigurationSupportTests {
|
||||
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
|
||||
assertNotNull(adapter);
|
||||
|
||||
List<ServerHttpMessageReader<?>> readers = adapter.getMessageReaders();
|
||||
assertEquals(7, readers.size());
|
||||
List<HttpMessageReader<?>> readers = adapter.getMessageReaders();
|
||||
assertEquals(8, readers.size());
|
||||
|
||||
assertHasMessageReader(readers, byte[].class, APPLICATION_OCTET_STREAM);
|
||||
assertHasMessageReader(readers, ByteBuffer.class, APPLICATION_OCTET_STREAM);
|
||||
@@ -160,7 +159,7 @@ public class WebFluxConfigurationSupportTests {
|
||||
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
|
||||
assertNotNull(adapter);
|
||||
|
||||
List<ServerHttpMessageReader<?>> messageReaders = adapter.getMessageReaders();
|
||||
List<HttpMessageReader<?>> messageReaders = adapter.getMessageReaders();
|
||||
assertEquals(2, messageReaders.size());
|
||||
|
||||
assertHasMessageReader(messageReaders, String.class, TEXT_PLAIN);
|
||||
@@ -177,7 +176,7 @@ public class WebFluxConfigurationSupportTests {
|
||||
|
||||
assertEquals(0, handler.getOrder());
|
||||
|
||||
List<ServerHttpMessageWriter<?>> writers = handler.getMessageWriters();
|
||||
List<HttpMessageWriter<?>> writers = handler.getMessageWriters();
|
||||
assertEquals(9, writers.size());
|
||||
|
||||
assertHasMessageWriter(writers, byte[].class, APPLICATION_OCTET_STREAM);
|
||||
@@ -203,7 +202,7 @@ public class WebFluxConfigurationSupportTests {
|
||||
|
||||
assertEquals(100, handler.getOrder());
|
||||
|
||||
List<ServerHttpMessageWriter<?>> writers = handler.getMessageWriters();
|
||||
List<HttpMessageWriter<?>> writers = handler.getMessageWriters();
|
||||
assertEquals(9, writers.size());
|
||||
|
||||
assertHasMessageWriter(writers, byte[].class, APPLICATION_OCTET_STREAM);
|
||||
@@ -259,12 +258,12 @@ public class WebFluxConfigurationSupportTests {
|
||||
}
|
||||
|
||||
|
||||
private void assertHasMessageReader(List<ServerHttpMessageReader<?>> readers, Class<?> clazz, MediaType mediaType) {
|
||||
private void assertHasMessageReader(List<HttpMessageReader<?>> 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<ServerHttpMessageWriter<?>> writers, Class<?> clazz, MediaType mediaType) {
|
||||
private void assertHasMessageWriter(List<HttpMessageWriter<?>> writers, Class<?> clazz, MediaType mediaType) {
|
||||
ResolvableType type = ResolvableType.forClass(clazz);
|
||||
assertTrue(writers.stream().anyMatch(c -> mediaType == null || c.canWrite(type, mediaType)));
|
||||
}
|
||||
@@ -297,23 +296,12 @@ public class WebFluxConfigurationSupportTests {
|
||||
static class CustomMessageConverterConfig extends WebFluxConfigurationSupport {
|
||||
|
||||
@Override
|
||||
protected void configureMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
|
||||
messageReaders.add(new DecoderHttpMessageReader<>(StringDecoder.textPlainOnly(true)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
|
||||
messageWriters.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.textPlainOnly()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extendMessageReaders(List<ServerHttpMessageReader<?>> messageReaders) {
|
||||
messageReaders.add(new DecoderHttpMessageReader<>(new Jaxb2XmlDecoder()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void extendMessageWriters(List<ServerHttpMessageWriter<?>> messageWriters) {
|
||||
messageWriters.add(new EncoderHttpMessageWriter<>(new Jaxb2XmlEncoder()));
|
||||
protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
|
||||
configurer.registerDefaults(false);
|
||||
configurer.customCodec().decoder(StringDecoder.textPlainOnly(true));
|
||||
configurer.customCodec().decoder(new Jaxb2XmlDecoder());
|
||||
configurer.customCodec().encoder(CharSequenceEncoder.textPlainOnly());
|
||||
configurer.customCodec().encoder(new Jaxb2XmlEncoder());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,16 +120,19 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
@Bean
|
||||
public HandlerMapping handlerMapping(RouterFunction<?> routerFunction,
|
||||
ApplicationContext applicationContext) {
|
||||
|
||||
return RouterFunctions.toHandlerMapping(routerFunction,
|
||||
new HandlerStrategies() {
|
||||
@Override
|
||||
public Supplier<Stream<HttpMessageReader<?>>> messageReaders() {
|
||||
return () -> getMessageReaders().stream().map(reader -> (HttpMessageReader<?>) reader);
|
||||
return () -> getMessageCodecsConfigurer().getReaders().stream()
|
||||
.map(reader -> (HttpMessageReader<?>) reader);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Stream<HttpMessageWriter<?>>> messageWriters() {
|
||||
return () -> getMessageWriters().stream().map(writer -> (HttpMessageWriter<?>) writer);
|
||||
return () -> getMessageCodecsConfigurer().getWriters().stream()
|
||||
.map(writer -> (HttpMessageWriter<?>) writer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
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<ServerHttpMessageReader<?>> readers = new ArrayList<>();
|
||||
List<HttpMessageReader<?>> readers = new ArrayList<>();
|
||||
readers.add(new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes(true)));
|
||||
return new HttpEntityArgumentResolver(readers, new ReactiveAdapterRegistry());
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
@@ -302,7 +302,7 @@ public class MessageReaderArgumentResolverTests {
|
||||
|
||||
@SuppressWarnings("Convert2MethodRef")
|
||||
private AbstractMessageReaderArgumentResolver resolver(Decoder<?>... decoders) {
|
||||
List<ServerHttpMessageReader<?>> readers = new ArrayList<>();
|
||||
List<HttpMessageReader<?>> readers = new ArrayList<>();
|
||||
Arrays.asList(decoders).forEach(decoder -> readers.add(new DecoderHttpMessageReader<>(decoder)));
|
||||
return new AbstractMessageReaderArgumentResolver(readers) {
|
||||
@Override
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
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(ServerHttpMessageWriter<?>... writers) {
|
||||
List<ServerHttpMessageWriter<?>> writerList;
|
||||
private AbstractMessageWriterResultHandler initResultHandler(HttpMessageWriter<?>... writers) {
|
||||
List<HttpMessageWriter<?>> 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);
|
||||
|
||||
ServerHttpMessageWriter<?> writer = new EncoderHttpMessageWriter<>(new ByteBufferEncoder());
|
||||
HttpMessageWriter<?> 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.ServerHttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
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<ServerHttpMessageReader<?>> readers = new ArrayList<>();
|
||||
List<HttpMessageReader<?>> readers = new ArrayList<>();
|
||||
readers.add(new DecoderHttpMessageReader<>(StringDecoder.allMimeTypes(true)));
|
||||
this.resolver = new RequestBodyArgumentResolver(readers, new ReactiveAdapterRegistry());
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.springframework.core.codec.ByteBufferEncoder;
|
||||
import org.springframework.core.codec.CharSequenceEncoder;
|
||||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
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<ServerHttpMessageWriter<?>> writerList = new ArrayList<>(5);
|
||||
List<HttpMessageWriter<?>> writerList = new ArrayList<>(5);
|
||||
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
|
||||
writerList.add(new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()));
|
||||
writerList.add(new ResourceHttpMessageWriter());
|
||||
|
||||
@@ -44,7 +44,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.codec.EncoderHttpMessageWriter;
|
||||
import org.springframework.http.codec.ResourceHttpMessageWriter;
|
||||
import org.springframework.http.codec.ServerHttpMessageWriter;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
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(ServerHttpMessageWriter<?>... writers) {
|
||||
List<ServerHttpMessageWriter<?>> writerList;
|
||||
private ResponseEntityResultHandler createHandler(HttpMessageWriter<?>... writers) {
|
||||
List<HttpMessageWriter<?>> writerList;
|
||||
if (ObjectUtils.isEmpty(writers)) {
|
||||
writerList = new ArrayList<>();
|
||||
writerList.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
|
||||
|
||||
Reference in New Issue
Block a user