diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java index db73d7a838..ef8a9fab75 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java @@ -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 resolvers = registry.getViewResolvers(); ServerResponseResultHandler handler = new ServerResponseResultHandler(); - handler.setMessageCodecConfigurer(serverCodecConfigurer()); + handler.setMessageWriters(serverCodecConfigurer().getWriters()); handler.setViewResolvers(resolvers); handler.setOrder(registry.getOrder() + 1); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java index d799884000..016162414f 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java @@ -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> 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. - *

By default this is set to {@link ServerCodecConfigurer} with defaults. + *

By default this is set to the {@link ServerCodecConfigurer}'s defaults. */ - public void setMessageCodecConfigurer(ServerCodecConfigurer configurer) { - this.messageCodecConfigurer = configurer; + public void setMessageReaders(List> 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); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java index d0c1aa4002..1130f93218 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java @@ -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> messageWriters = Collections.emptyList(); private List viewResolvers = Collections.emptyList(); @@ -50,11 +49,12 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia /** - * Configure HTTP message readers to de-serialize the request body with. - *

By default this is set to {@link ServerCodecConfigurer} with defaults. + * Configure HTTP message writers to serialize the request body with. + *

By default this is set to {@link ServerCodecConfigurer}'s default writers. */ - public void setMessageCodecConfigurer(ServerCodecConfigurer configurer) { - this.messageCodecConfigurer = configurer; + public void setMessageWriters(List> configurer) { + Assert.notNull(messageWriters, "'messageWriters' must not be null"); + this.messageWriters = configurer; } public void setViewResolvers(List 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> messageWriters() { - return (messageCodecConfigurer != null ? - messageCodecConfigurer.getWriters() : Collections.emptyList()); + return messageWriters; } @Override public List viewResolvers() { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java index f99c963745..7078d63950 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java @@ -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> 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 customResolvers; - @Nullable private final List> messageReaders; private final boolean modelAttributeSupported; @@ -337,10 +337,10 @@ class ControllerMethodResolver { private final List result = new ArrayList<>(); private ArgumentResolverRegistrar(ArgumentResolverConfigurer resolvers, - @Nullable ServerCodecConfigurer codecs, boolean modelAttribute) { + List> 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>, 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> 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); } } } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java index 76d29bf219..0279ebad89 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java @@ -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> 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. - *

By default this is set to {@link ServerCodecConfigurer} with defaults. + *

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> 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> 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); } diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java index ed08ee0744..bc244cc2ef 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/WebFluxConfigurationSupportTests.java @@ -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> readers = adapter.getMessageCodecConfigurer().getReaders(); + List> 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> messageReaders = adapter.getMessageCodecConfigurer().getReaders(); + List> messageReaders = adapter.getMessageReaders(); assertEquals(2, messageReaders.size()); assertHasMessageReader(messageReaders, forClass(String.class), TEXT_PLAIN); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java index 4b4f2dc88a..231df7589c 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/support/RouterFunctionMappingTests.java @@ -66,7 +66,7 @@ public class RouterFunctionMappingTests { RouterFunction routerFunction = request -> Mono.just(handlerFunction); RouterFunctionMapping mapping = new RouterFunctionMapping(routerFunction); - mapping.setMessageCodecConfigurer(this.codecConfigurer); + mapping.setMessageReaders(this.codecConfigurer.getReaders()); Mono result = mapping.getHandler(this.exchange); @@ -80,7 +80,7 @@ public class RouterFunctionMappingTests { public void noMatch() { RouterFunction routerFunction = request -> Mono.empty(); RouterFunctionMapping mapping = new RouterFunctionMapping(routerFunction); - mapping.setMessageCodecConfigurer(this.codecConfigurer); + mapping.setMessageReaders(this.codecConfigurer.getReaders()); Mono result = mapping.getHandler(this.exchange); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolverTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolverTests.java index ef8865454f..c07bcc43f3 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolverTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolverTests.java @@ -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);