Skip to content

Commit 4b92bf2

Browse files
committed
Split HttpMessageConverter into ~Reader and ~Writer
1 parent dca8078 commit 4b92bf2

File tree

39 files changed

+709
-558
lines changed

39 files changed

+709
-558
lines changed

spring-web-reactive/src/main/java/org/springframework/web/reactive/config/ViewResolverRegistry.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.springframework.core.Ordered;
2626
import org.springframework.util.Assert;
2727
import org.springframework.util.ObjectUtils;
28+
import org.springframework.web.reactive.result.view.HttpMessageWriterView;
2829
import org.springframework.web.reactive.result.view.UrlBasedViewResolver;
2930
import org.springframework.web.reactive.result.view.View;
3031
import org.springframework.web.reactive.result.view.ViewResolver;
@@ -97,9 +98,9 @@ public void viewResolver(ViewResolver viewResolver) {
9798
/**
9899
* Set default views associated with any view name and selected based on the
99100
* best match for the requested content type.
100-
* <p>Use {@link org.springframework.web.reactive.result.view.HttpMessageConverterView
101-
* HttpMessageConverterView} to adapt and use any existing
102-
* {@code HttpMessageConverter} (e.g. JSON, XML) as a {@code View}.
101+
* <p>Use {@link HttpMessageWriterView
102+
* HttpMessageWriterView} to adapt and use any existing
103+
* {@code HttpMessageWriter} (e.g. JSON, XML) as a {@code View}.
103104
*/
104105
public void defaultViews(View... defaultViews) {
105106
this.defaultViews.addAll(Arrays.asList(defaultViews));

spring-web-reactive/src/main/java/org/springframework/web/reactive/config/WebReactiveConfiguration.java

Lines changed: 90 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
import org.springframework.context.annotation.Configuration;
2929
import org.springframework.core.codec.ByteBufferDecoder;
3030
import org.springframework.core.codec.ByteBufferEncoder;
31-
import org.springframework.core.codec.Decoder;
3231
import org.springframework.core.codec.Encoder;
32+
import org.springframework.core.codec.ResourceDecoder;
3333
import org.springframework.core.codec.StringDecoder;
3434
import org.springframework.core.codec.StringEncoder;
3535
import org.springframework.core.convert.converter.Converter;
@@ -45,9 +45,11 @@
4545
import org.springframework.http.codec.json.JacksonJsonEncoder;
4646
import org.springframework.http.codec.xml.Jaxb2Decoder;
4747
import org.springframework.http.codec.xml.Jaxb2Encoder;
48-
import org.springframework.http.converter.reactive.CodecHttpMessageConverter;
49-
import org.springframework.http.converter.reactive.HttpMessageConverter;
50-
import org.springframework.http.converter.reactive.ResourceHttpMessageConverter;
48+
import org.springframework.http.converter.reactive.DecoderHttpMessageReader;
49+
import org.springframework.http.converter.reactive.EncoderHttpMessageWriter;
50+
import org.springframework.http.converter.reactive.HttpMessageReader;
51+
import org.springframework.http.converter.reactive.HttpMessageWriter;
52+
import org.springframework.http.converter.reactive.ResourceHttpMessageWriter;
5153
import org.springframework.util.ClassUtils;
5254
import org.springframework.validation.Errors;
5355
import org.springframework.validation.Validator;
@@ -87,7 +89,9 @@ public class WebReactiveConfiguration implements ApplicationContextAware {
8789

8890
private PathMatchConfigurer pathMatchConfigurer;
8991

90-
private List<HttpMessageConverter<?>> messageConverters;
92+
private List<HttpMessageReader<?>> messageReaders;
93+
94+
private List<HttpMessageWriter<?>> messageWriters;
9195

9296
private ApplicationContext applicationContext;
9397

@@ -189,7 +193,7 @@ public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
189193
adapter.setCustomArgumentResolvers(resolvers);
190194
}
191195

192-
adapter.setMessageConverters(getMessageConverters());
196+
adapter.setMessageReaders(getMessageReaders());
193197
adapter.setConversionService(mvcConversionService());
194198
adapter.setValidator(mvcValidator());
195199

@@ -210,65 +214,54 @@ protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolver
210214
}
211215

212216
/**
213-
* Main method to access message converters to use for decoding
214-
* controller method arguments and encoding return values.
215-
* <p>Use {@link #configureMessageConverters} to configure the list or
216-
* {@link #extendMessageConverters} to add in addition to the default ones.
217+
* Main method to access message readers to use for decoding
218+
* controller method arguments with.
219+
* <p>Use {@link #configureMessageReaders} to configure the list or
220+
* {@link #extendMessageReaders} to add in addition to the default ones.
217221
*/
218-
protected final List<HttpMessageConverter<?>> getMessageConverters() {
219-
if (this.messageConverters == null) {
220-
this.messageConverters = new ArrayList<>();
221-
configureMessageConverters(this.messageConverters);
222-
if (this.messageConverters.isEmpty()) {
223-
addDefaultHttpMessageConverters(this.messageConverters);
222+
protected final List<HttpMessageReader<?>> getMessageReaders() {
223+
if (this.messageReaders == null) {
224+
this.messageReaders = new ArrayList<>();
225+
configureMessageReaders(this.messageReaders);
226+
if (this.messageReaders.isEmpty()) {
227+
addDefaultHttpMessageReaders(this.messageReaders);
224228
}
225-
extendMessageConverters(this.messageConverters);
229+
extendMessageReaders(this.messageReaders);
226230
}
227-
return this.messageConverters;
231+
return this.messageReaders;
228232
}
229233

230234
/**
231-
* Override to configure the message converters to use for decoding
232-
* controller method arguments and encoding return values.
233-
* <p>If no converters are specified, default will be added via
234-
* {@link #addDefaultHttpMessageConverters}.
235-
* @param converters a list to add converters to, initially an empty
235+
* Override to configure the message readers to use for decoding
236+
* controller method arguments.
237+
* <p>If no message readres are specified, default will be added via
238+
* {@link #addDefaultHttpMessageReaders}.
239+
* @param messageReaders a list to add message readers to, initially an empty
236240
*/
237-
protected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
241+
protected void configureMessageReaders(List<HttpMessageReader<?>> messageReaders) {
238242
}
239243

240244
/**
241245
* Adds default converters that sub-classes can call from
242-
* {@link #configureMessageConverters(List)}.
246+
* {@link #configureMessageReaders(List)}.
243247
*/
244-
protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> converters) {
245-
List<Encoder<?>> sseDataEncoders = new ArrayList<>();
246-
converters.add(converter(new ByteBufferEncoder(), new ByteBufferDecoder()));
247-
converters.add(converter(new StringEncoder(), new StringDecoder()));
248-
converters.add(new ResourceHttpMessageConverter());
248+
protected final void addDefaultHttpMessageReaders(List<HttpMessageReader<?>> readers) {
249+
readers.add(new DecoderHttpMessageReader<>(new ByteBufferDecoder()));
250+
readers.add(new DecoderHttpMessageReader<>(new StringDecoder()));
251+
readers.add(new DecoderHttpMessageReader<>(new ResourceDecoder()));
249252
if (jaxb2Present) {
250-
converters.add(converter(new Jaxb2Encoder(), new Jaxb2Decoder()));
253+
readers.add(new DecoderHttpMessageReader<>(new Jaxb2Decoder()));
251254
}
252255
if (jackson2Present) {
253-
JacksonJsonEncoder jacksonEncoder = new JacksonJsonEncoder();
254-
JacksonJsonDecoder jacksonDecoder = new JacksonJsonDecoder();
255-
converters.add(converter(jacksonEncoder, jacksonDecoder));
256-
sseDataEncoders.add(jacksonEncoder);
257-
} else {
258-
256+
readers.add(new DecoderHttpMessageReader<>(new JacksonJsonDecoder()));
259257
}
260-
converters.add(converter(new SseEventEncoder(sseDataEncoders), null));
261-
}
262-
263-
private static <T> HttpMessageConverter<T> converter(Encoder<T> encoder, Decoder<T> decoder) {
264-
return new CodecHttpMessageConverter<>(encoder, decoder);
265258
}
266259

267260
/**
268-
* Override this to modify the list of converters after it has been
261+
* Override this to modify the list of message readers after it has been
269262
* configured, for example to add some in addition to the default ones.
270263
*/
271-
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
264+
protected void extendMessageReaders(List<HttpMessageReader<?>> messageReaders) {
272265
}
273266

274267
@Bean
@@ -345,16 +338,67 @@ public SimpleResultHandler simpleResultHandler() {
345338

346339
@Bean
347340
public ResponseEntityResultHandler responseEntityResultHandler() {
348-
return new ResponseEntityResultHandler(getMessageConverters(), mvcConversionService(),
341+
return new ResponseEntityResultHandler(getMessageWriters(), mvcConversionService(),
349342
mvcContentTypeResolver());
350343
}
351344

352345
@Bean
353346
public ResponseBodyResultHandler responseBodyResultHandler() {
354-
return new ResponseBodyResultHandler(getMessageConverters(), mvcConversionService(),
347+
return new ResponseBodyResultHandler(getMessageWriters(), mvcConversionService(),
355348
mvcContentTypeResolver());
356349
}
357350

351+
/**
352+
* Main method to access message writers to use for encoding return values.
353+
* <p>Use {@link #configureMessageWriters(List)} to configure the list or
354+
* {@link #extendMessageWriters(List)} to add in addition to the default ones.
355+
*/
356+
protected final List<HttpMessageWriter<?>> getMessageWriters() {
357+
if (this.messageWriters == null) {
358+
this.messageWriters = new ArrayList<>();
359+
configureMessageWriters(this.messageWriters);
360+
if (this.messageWriters.isEmpty()) {
361+
addDefaultHttpMessageWriters(this.messageWriters);
362+
}
363+
extendMessageWriters(this.messageWriters);
364+
}
365+
return this.messageWriters;
366+
}
367+
/**
368+
* Override to configure the message writers to use for encoding
369+
* return values.
370+
* <p>If no message readers are specified, default will be added via
371+
* {@link #addDefaultHttpMessageWriters}.
372+
* @param messageWriters a list to add message writers to, initially an empty
373+
*/
374+
protected void configureMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
375+
}
376+
/**
377+
* Adds default converters that sub-classes can call from
378+
* {@link #configureMessageWriters(List)}.
379+
*/
380+
protected final void addDefaultHttpMessageWriters(List<HttpMessageWriter<?>> writers) {
381+
List<Encoder<?>> sseDataEncoders = new ArrayList<>();
382+
writers.add(new EncoderHttpMessageWriter<>(new ByteBufferEncoder()));
383+
writers.add(new EncoderHttpMessageWriter<>(new StringEncoder()));
384+
writers.add(new ResourceHttpMessageWriter());
385+
if (jaxb2Present) {
386+
writers.add(new EncoderHttpMessageWriter<>(new Jaxb2Encoder()));
387+
}
388+
if (jackson2Present) {
389+
JacksonJsonEncoder jacksonEncoder = new JacksonJsonEncoder();
390+
writers.add(new EncoderHttpMessageWriter<>(jacksonEncoder));
391+
sseDataEncoders.add(jacksonEncoder);
392+
}
393+
writers.add(new EncoderHttpMessageWriter<>(new SseEventEncoder(sseDataEncoders)));
394+
}
395+
/**
396+
* Override this to modify the list of message writers after it has been
397+
* configured, for example to add some in addition to the default ones.
398+
*/
399+
protected void extendMessageWriters(List<HttpMessageWriter<?>> messageWriters) {
400+
}
401+
358402
@Bean
359403
public ViewResolutionResultHandler viewResolutionResultHandler() {
360404
ViewResolverRegistry registry = new ViewResolverRegistry(this.applicationContext);
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import org.springframework.core.convert.ConversionService;
3131
import org.springframework.core.convert.TypeDescriptor;
3232
import org.springframework.http.MediaType;
33-
import org.springframework.http.converter.reactive.HttpMessageConverter;
33+
import org.springframework.http.converter.reactive.HttpMessageReader;
3434
import org.springframework.http.server.reactive.ServerHttpRequest;
3535
import org.springframework.util.Assert;
3636
import org.springframework.util.ObjectUtils;
@@ -45,7 +45,7 @@
4545

4646
/**
4747
* Abstract base class for argument resolvers that resolve method arguments
48-
* by reading the request body with an {@link HttpMessageConverter}.
48+
* by reading the request body with an {@link HttpMessageReader}.
4949
*
5050
* <p>Applies validation if the method argument is annotated with
5151
* {@code @javax.validation.Valid} or
@@ -55,14 +55,14 @@
5555
* @author Rossen Stoyanchev
5656
* @since 5.0
5757
*/
58-
public abstract class AbstractMessageConverterArgumentResolver {
58+
public abstract class AbstractMessageReaderArgumentResolver {
5959

6060
private static final TypeDescriptor MONO_TYPE = TypeDescriptor.valueOf(Mono.class);
6161

6262
private static final TypeDescriptor FLUX_TYPE = TypeDescriptor.valueOf(Flux.class);
6363

6464

65-
private final List<HttpMessageConverter<?>> messageConverters;
65+
private final List<HttpMessageReader<?>> messageReaders;
6666

6767
private final ConversionService conversionService;
6868

@@ -73,19 +73,19 @@ public abstract class AbstractMessageConverterArgumentResolver {
7373

7474
/**
7575
* Constructor with message converters and a ConversionService.
76-
* @param converters converters for reading the request body with
76+
* @param messageReaders readers to convert from the request body
7777
* @param service for converting to other reactive types from Flux and Mono
7878
* @param validator validator to validate decoded objects with
7979
*/
80-
protected AbstractMessageConverterArgumentResolver(List<HttpMessageConverter<?>> converters,
80+
protected AbstractMessageReaderArgumentResolver(List<HttpMessageReader<?>> messageReaders,
8181
ConversionService service, Validator validator) {
8282

83-
Assert.notEmpty(converters, "At least one message converter is required.");
83+
Assert.notEmpty(messageReaders, "At least one message reader is required.");
8484
Assert.notNull(service, "'conversionService' is required.");
85-
this.messageConverters = converters;
85+
this.messageReaders = messageReaders;
8686
this.conversionService = service;
8787
this.validator = validator;
88-
this.supportedMediaTypes = converters.stream()
88+
this.supportedMediaTypes = messageReaders.stream()
8989
.flatMap(converter -> converter.getReadableMediaTypes().stream())
9090
.collect(Collectors.toList());
9191
}
@@ -94,8 +94,8 @@ protected AbstractMessageConverterArgumentResolver(List<HttpMessageConverter<?>>
9494
/**
9595
* Return the configured message converters.
9696
*/
97-
public List<HttpMessageConverter<?>> getMessageConverters() {
98-
return this.messageConverters;
97+
public List<HttpMessageReader<?>> getMessageReaders() {
98+
return this.messageReaders;
9999
}
100100

101101
/**
@@ -124,10 +124,10 @@ protected Mono<Object> readBody(MethodParameter bodyParameter, boolean isBodyReq
124124
mediaType = MediaType.APPLICATION_OCTET_STREAM;
125125
}
126126

127-
for (HttpMessageConverter<?> converter : getMessageConverters()) {
128-
if (converter.canRead(elementType, mediaType)) {
127+
for (HttpMessageReader<?> reader : getMessageReaders()) {
128+
if (reader.canRead(elementType, mediaType)) {
129129
if (convertFromFlux) {
130-
Flux<?> flux = converter.read(elementType, request)
130+
Flux<?> flux = reader.read(elementType, request)
131131
.onErrorResumeWith(ex -> Flux.error(getReadError(ex, bodyParameter)));
132132
if (checkRequired(bodyParameter, isBodyRequired)) {
133133
flux = flux.switchIfEmpty(Flux.error(getRequiredBodyError(bodyParameter)));
@@ -138,7 +138,7 @@ protected Mono<Object> readBody(MethodParameter bodyParameter, boolean isBodyReq
138138
return Mono.just(getConversionService().convert(flux, FLUX_TYPE, typeDescriptor));
139139
}
140140
else {
141-
Mono<?> mono = converter.readMono(elementType, request)
141+
Mono<?> mono = reader.readMono(elementType, request)
142142
.otherwise(ex -> Mono.error(getReadError(ex, bodyParameter)));
143143
if (checkRequired(bodyParameter, isBodyRequired)) {
144144
mono = mono.otherwiseIfEmpty(Mono.error(getRequiredBodyError(bodyParameter)));

0 commit comments

Comments
 (0)