Use list of HttpMessage[Reader|Writer]s instead of CodecConfigurer

This commit changes all consumers of CodecConfigurer to consume a `List`
of HttpMessageReaders or HttpMessageWriters instead of consuming the
Server- or ClientCodecConfigurer directly.

Issue: SPR-15816
This commit is contained in:
Arjen Poutsma 2017-07-26 16:21:46 +02:00
parent 1e07468d20
commit f3975776d4
8 changed files with 59 additions and 63 deletions

View File

@ -192,7 +192,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
public RouterFunctionMapping routerFunctionMapping() {
RouterFunctionMapping mapping = createRouterFunctionMapping();
mapping.setOrder(-1); // go before RequestMappingHandlerMapping
mapping.setMessageCodecConfigurer(serverCodecConfigurer());
mapping.setMessageReaders(serverCodecConfigurer().getReaders());
mapping.setCorsConfigurations(getCorsConfigurations());
return mapping;
@ -247,7 +247,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
adapter.setMessageCodecConfigurer(serverCodecConfigurer());
adapter.setMessageReaders(serverCodecConfigurer().getReaders());
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
adapter.setReactiveAdapterRegistry(webFluxAdapterRegistry());
@ -425,7 +425,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
List<ViewResolver> resolvers = registry.getViewResolvers();
ServerResponseResultHandler handler = new ServerResponseResultHandler();
handler.setMessageCodecConfigurer(serverCodecConfigurer());
handler.setMessageWriters(serverCodecConfigurer().getWriters());
handler.setViewResolvers(resolvers);
handler.setOrder(registry.getOrder() + 1);

View File

@ -23,6 +23,7 @@ import reactor.core.publisher.Mono;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -48,8 +49,7 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini
@Nullable
private RouterFunction<?> routerFunction;
@Nullable
private ServerCodecConfigurer messageCodecConfigurer;
private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();
/**
@ -72,18 +72,20 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini
/**
* Configure HTTP message readers to de-serialize the request body with.
* <p>By default this is set to {@link ServerCodecConfigurer} with defaults.
* <p>By default this is set to the {@link ServerCodecConfigurer}'s defaults.
*/
public void setMessageCodecConfigurer(ServerCodecConfigurer configurer) {
this.messageCodecConfigurer = configurer;
public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
Assert.notNull(messageReaders, "'messageReaders' must not be null");
this.messageReaders = messageReaders;
}
@Override
public void afterPropertiesSet() throws Exception {
if (this.messageCodecConfigurer == null) {
this.messageCodecConfigurer = ServerCodecConfigurer.create();
if (CollectionUtils.isEmpty(this.messageReaders)) {
ServerCodecConfigurer codecConfigurer = ServerCodecConfigurer.create();
this.messageReaders = codecConfigurer.getReaders();
}
if (this.routerFunction == null) {
initRouterFunctions();
}
@ -120,8 +122,7 @@ public class RouterFunctionMapping extends AbstractHandlerMapping implements Ini
@Override
protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
if (this.routerFunction != null) {
Assert.state(this.messageCodecConfigurer != null, "No ServerCodecConfigurer set");
ServerRequest request = ServerRequest.create(exchange, this.messageCodecConfigurer.getReaders());
ServerRequest request = ServerRequest.create(exchange, this.messageReaders);
exchange.getAttributes().put(RouterFunctions.REQUEST_ATTRIBUTE, request);
return this.routerFunction.route(request);
}

View File

@ -25,8 +25,8 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Ordered;
import org.springframework.http.codec.HttpMessageWriter;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.HandlerResultHandler;
import org.springframework.web.reactive.function.server.ServerResponse;
@ -41,8 +41,7 @@ import org.springframework.web.server.ServerWebExchange;
*/
public class ServerResponseResultHandler implements HandlerResultHandler, InitializingBean, Ordered {
@Nullable
private ServerCodecConfigurer messageCodecConfigurer;
private List<HttpMessageWriter<?>> messageWriters = Collections.emptyList();
private List<ViewResolver> viewResolvers = Collections.emptyList();
@ -50,11 +49,12 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia
/**
* Configure HTTP message readers to de-serialize the request body with.
* <p>By default this is set to {@link ServerCodecConfigurer} with defaults.
* Configure HTTP message writers to serialize the request body with.
* <p>By default this is set to {@link ServerCodecConfigurer}'s default writers.
*/
public void setMessageCodecConfigurer(ServerCodecConfigurer configurer) {
this.messageCodecConfigurer = configurer;
public void setMessageWriters(List<HttpMessageWriter<?>> configurer) {
Assert.notNull(messageWriters, "'messageWriters' must not be null");
this.messageWriters = configurer;
}
public void setViewResolvers(List<ViewResolver> viewResolvers) {
@ -79,8 +79,8 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia
@Override
public void afterPropertiesSet() throws Exception {
if (this.messageCodecConfigurer == null) {
throw new IllegalArgumentException("Property 'messageCodecConfigurer' is required");
if (CollectionUtils.isEmpty(this.messageWriters)) {
throw new IllegalArgumentException("Property 'messageWriters' is required");
}
}
@ -96,8 +96,7 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia
return response.writeTo(exchange, new ServerResponse.Context() {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return (messageCodecConfigurer != null ?
messageCodecConfigurer.getWriters() : Collections.emptyList());
return messageWriters;
}
@Override
public List<ViewResolver> viewResolvers() {

View File

@ -18,6 +18,7 @@ package org.springframework.web.reactive.result.method.annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@ -37,9 +38,9 @@ import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
@ -52,7 +53,7 @@ import org.springframework.web.reactive.result.method.InvocableHandlerMethod;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod;
import static org.springframework.core.MethodIntrospector.*;
import static org.springframework.core.MethodIntrospector.selectMethods;
/**
* Package-private class to assist {@link RequestMappingHandlerAdapter} with
@ -98,17 +99,17 @@ class ControllerMethodResolver {
ControllerMethodResolver(ArgumentResolverConfigurer argumentResolvers,
ServerCodecConfigurer messageCodecs, ReactiveAdapterRegistry reactiveRegistry,
List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry reactiveRegistry,
ConfigurableApplicationContext context) {
Assert.notNull(argumentResolvers, "ArgumentResolverConfigurer is required");
Assert.notNull(messageCodecs, "ServerCodecConfigurer is required");
Assert.notNull(messageReaders, "'messageReaders' is required");
Assert.notNull(reactiveRegistry, "ReactiveAdapterRegistry is required");
Assert.notNull(context, "ApplicationContext is required");
ArgumentResolverRegistrar registrar;
registrar= ArgumentResolverRegistrar.configurer(argumentResolvers).basic();
registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).basic();
addResolversTo(registrar, reactiveRegistry, context);
this.initBinderResolvers = registrar.getSyncResolvers();
@ -116,7 +117,7 @@ class ControllerMethodResolver {
addResolversTo(registrar, reactiveRegistry, context);
this.modelAttributeResolvers = registrar.getResolvers();
registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).fullSupport(messageCodecs);
registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).fullSupport(messageReaders);
addResolversTo(registrar, reactiveRegistry, context);
this.requestMappingResolvers = registrar.getResolvers();
@ -329,7 +330,6 @@ class ControllerMethodResolver {
private final List<HandlerMethodArgumentResolver> customResolvers;
@Nullable
private final List<HttpMessageReader<?>> messageReaders;
private final boolean modelAttributeSupported;
@ -337,10 +337,10 @@ class ControllerMethodResolver {
private final List<HandlerMethodArgumentResolver> result = new ArrayList<>();
private ArgumentResolverRegistrar(ArgumentResolverConfigurer resolvers,
@Nullable ServerCodecConfigurer codecs, boolean modelAttribute) {
List<HttpMessageReader<?>> messageReaders, boolean modelAttribute) {
this.customResolvers = resolvers.getCustomResolvers();
this.messageReaders = (codecs != null ? codecs.getReaders() : null);
this.messageReaders = messageReaders;
this.modelAttributeSupported = modelAttribute;
}
@ -350,7 +350,7 @@ class ControllerMethodResolver {
}
public void addIfRequestBody(Function<List<HttpMessageReader<?>>, HandlerMethodArgumentResolver> function) {
if (this.messageReaders != null) {
if (!CollectionUtils.isEmpty(this.messageReaders)) {
add(function.apply(this.messageReaders));
}
}
@ -390,16 +390,16 @@ class ControllerMethodResolver {
this.resolvers = configurer;
}
public ArgumentResolverRegistrar fullSupport(ServerCodecConfigurer codecs) {
return new ArgumentResolverRegistrar(this.resolvers, codecs, true);
public ArgumentResolverRegistrar fullSupport(List<HttpMessageReader<?>> httpMessageReaders) {
return new ArgumentResolverRegistrar(this.resolvers, httpMessageReaders, true);
}
public ArgumentResolverRegistrar modelAttributeSupport() {
return new ArgumentResolverRegistrar(this.resolvers, null, true);
return new ArgumentResolverRegistrar(this.resolvers, Collections.emptyList(), true);
}
public ArgumentResolverRegistrar basic() {
return new ArgumentResolverRegistrar(this.resolvers, null, false);
return new ArgumentResolverRegistrar(this.resolvers, Collections.emptyList(), false);
}
}
}

View File

@ -16,6 +16,7 @@
package org.springframework.web.reactive.result.method.annotation;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@ -28,9 +29,11 @@ import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.http.codec.HttpMessageReader;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.BindingContext;
@ -50,8 +53,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
private static final Log logger = LogFactory.getLog(RequestMappingHandlerAdapter.class);
@Nullable
private ServerCodecConfigurer messageCodecConfigurer;
private List<HttpMessageReader<?>> messageReaders = Collections.emptyList();
@Nullable
private WebBindingInitializer webBindingInitializer;
@ -74,18 +76,18 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
/**
* Configure HTTP message readers to de-serialize the request body with.
* <p>By default this is set to {@link ServerCodecConfigurer} with defaults.
* <p>By default this is set to {@link ServerCodecConfigurer}'s readers with defaults.
*/
public void setMessageCodecConfigurer(@Nullable ServerCodecConfigurer configurer) {
this.messageCodecConfigurer = configurer;
public void setMessageReaders(List<HttpMessageReader<?>> messageReaders) {
Assert.notNull(messageReaders, "'messageReaders' must not be null");
this.messageReaders = messageReaders;
}
/**
* Return the configurer for HTTP message readers.
*/
@Nullable
public ServerCodecConfigurer getMessageCodecConfigurer() {
return this.messageCodecConfigurer;
public List<HttpMessageReader<?>> getMessageReaders() {
return this.messageReaders;
}
/**
@ -153,8 +155,9 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.applicationContext, "ApplicationContext is required");
if (this.messageCodecConfigurer == null) {
this.messageCodecConfigurer = ServerCodecConfigurer.create();
if (CollectionUtils.isEmpty(this.messageReaders)) {
ServerCodecConfigurer codecConfigurer = ServerCodecConfigurer.create();
this.messageReaders = codecConfigurer.getReaders();
}
if (this.argumentResolverConfigurer == null) {
this.argumentResolverConfigurer = new ArgumentResolverConfigurer();
@ -164,7 +167,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
}
this.methodResolver = new ControllerMethodResolver(this.argumentResolverConfigurer,
this.messageCodecConfigurer, this.reactiveAdapterRegistry, this.applicationContext);
this.messageReaders, this.reactiveAdapterRegistry, this.applicationContext);
this.modelInitializer = new ModelInitializer(this.reactiveAdapterRegistry);
}

View File

@ -20,7 +20,6 @@ import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.List;
import javax.xml.bind.annotation.XmlRootElement;
import org.junit.Test;
@ -66,11 +65,7 @@ import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebHandler;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import static org.springframework.core.ResolvableType.forClass;
import static org.springframework.core.ResolvableType.forClassWithGenerics;
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;
@ -137,7 +132,7 @@ public class WebFluxConfigurationSupportTests {
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
assertNotNull(adapter);
List<HttpMessageReader<?>> readers = adapter.getMessageCodecConfigurer().getReaders();
List<HttpMessageReader<?>> readers = adapter.getMessageReaders();
assertEquals(12, readers.size());
assertHasMessageReader(readers, forClass(byte[].class), APPLICATION_OCTET_STREAM);
@ -172,7 +167,7 @@ public class WebFluxConfigurationSupportTests {
RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class);
assertNotNull(adapter);
List<HttpMessageReader<?>> messageReaders = adapter.getMessageCodecConfigurer().getReaders();
List<HttpMessageReader<?>> messageReaders = adapter.getMessageReaders();
assertEquals(2, messageReaders.size());
assertHasMessageReader(messageReaders, forClass(String.class), TEXT_PLAIN);

View File

@ -66,7 +66,7 @@ public class RouterFunctionMappingTests {
RouterFunction<ServerResponse> routerFunction = request -> Mono.just(handlerFunction);
RouterFunctionMapping mapping = new RouterFunctionMapping(routerFunction);
mapping.setMessageCodecConfigurer(this.codecConfigurer);
mapping.setMessageReaders(this.codecConfigurer.getReaders());
Mono<Object> result = mapping.getHandler(this.exchange);
@ -80,7 +80,7 @@ public class RouterFunctionMappingTests {
public void noMatch() {
RouterFunction<ServerResponse> routerFunction = request -> Mono.empty();
RouterFunctionMapping mapping = new RouterFunctionMapping(routerFunction);
mapping.setMessageCodecConfigurer(this.codecConfigurer);
mapping.setMessageReaders(this.codecConfigurer.getReaders());
Mono<Object> result = mapping.getHandler(this.exchange);

View File

@ -17,7 +17,6 @@ package org.springframework.web.reactive.result.method.annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.Before;
@ -47,8 +46,7 @@ import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.*;
/**
* Unit tests for {@link ControllerMethodResolver}.
@ -77,7 +75,7 @@ public class ControllerMethodResolverTests {
applicationContext.refresh();
this.methodResolver = new ControllerMethodResolver(
resolvers, codecs, new ReactiveAdapterRegistry(), applicationContext);
resolvers, codecs.getReaders(), new ReactiveAdapterRegistry(), applicationContext);
Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::handle).method();
this.handlerMethod = new HandlerMethod(new TestController(), method);