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 4d923b5b16..43f2e812f9 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 @@ -235,7 +235,7 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @Bean public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); - adapter.setMessageReaders(getMessageCodecsConfigurer().getReaders()); + adapter.setMessageCodecConfigurer(getMessageCodecsConfigurer()); adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); adapter.setReactiveAdapterRegistry(webFluxAdapterRegistry()); 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 0af113cf4a..8a7619925b 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 @@ -17,7 +17,6 @@ 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; @@ -38,6 +37,7 @@ 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.util.Assert; import org.springframework.util.ReflectionUtils; import org.springframework.web.bind.annotation.InitBinder; @@ -96,33 +96,34 @@ class ControllerMethodResolver { new LinkedHashMap<>(64); - ControllerMethodResolver(ArgumentResolverConfigurer argumentResolverConfigurer, - List> messageReaders, ReactiveAdapterRegistry reactiveRegistry, - ConfigurableApplicationContext applicationContext) { + ControllerMethodResolver(ArgumentResolverConfigurer argumentResolvers, + ServerCodecConfigurer messageCodecs, ReactiveAdapterRegistry reactiveRegistry, + ConfigurableApplicationContext context) { - Assert.notNull(argumentResolverConfigurer, "ArgumentResolverConfigurer is required"); + Assert.notNull(argumentResolvers, "ArgumentResolverConfigurer is required"); + Assert.notNull(messageCodecs, "ServerCodecConfigurer is required"); Assert.notNull(reactiveRegistry, "ReactiveAdapterRegistry is required"); - Assert.notNull(applicationContext, "ConfigurableApplicationContext is required"); + Assert.notNull(context, "ApplicationContext is required"); ArgumentResolverRegistrar registrar; - registrar= ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).basic(); - addResolversTo(registrar, reactiveRegistry, applicationContext); + registrar= ArgumentResolverRegistrar.configurer(argumentResolvers).basic(); + addResolversTo(registrar, reactiveRegistry, context); this.initBinderResolvers = registrar.getSyncResolvers(); - registrar = ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).modelAttributeSupport(); - addResolversTo(registrar, reactiveRegistry, applicationContext); + registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).modelAttributeSupport(); + addResolversTo(registrar, reactiveRegistry, context); this.modelAttributeResolvers = registrar.getResolvers(); - registrar = ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).fullSupport(messageReaders); - addResolversTo(registrar, reactiveRegistry, applicationContext); + registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).fullSupport(messageCodecs); + addResolversTo(registrar, reactiveRegistry, context); this.requestMappingResolvers = registrar.getResolvers(); - registrar = ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).basic(); - addResolversTo(registrar, reactiveRegistry, applicationContext); + registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).basic(); + addResolversTo(registrar, reactiveRegistry, context); this.exceptionHandlerResolvers = registrar.getResolvers(); - initControllerAdviceCaches(applicationContext); + initControllerAdviceCaches(context); } private void addResolversTo(ArgumentResolverRegistrar registrar, @@ -333,11 +334,11 @@ class ControllerMethodResolver { private final List result = new ArrayList<>(); - private ArgumentResolverRegistrar(ArgumentResolverConfigurer configurer, - List> messageReaders, boolean modelAttribute) { + private ArgumentResolverRegistrar(ArgumentResolverConfigurer resolvers, + ServerCodecConfigurer codecs, boolean modelAttribute) { - this.customResolvers = configurer.getCustomResolvers(); - this.messageReaders = messageReaders != null ? new ArrayList<>(messageReaders) : null; + this.customResolvers = resolvers.getCustomResolvers(); + this.messageReaders = codecs != null ? codecs.getReaders() : null; this.modelAttributeSupported = modelAttribute; } @@ -382,25 +383,24 @@ class ControllerMethodResolver { public static class Builder { - private final ArgumentResolverConfigurer configurer; + private final ArgumentResolverConfigurer resolvers; public Builder(ArgumentResolverConfigurer configurer) { - this.configurer = configurer; + this.resolvers = configurer; } - public ArgumentResolverRegistrar fullSupport(List> readers) { - Assert.notEmpty(readers, "No message readers"); - return new ArgumentResolverRegistrar(this.configurer, readers, true); + public ArgumentResolverRegistrar fullSupport(ServerCodecConfigurer codecs) { + return new ArgumentResolverRegistrar(this.resolvers, codecs, true); } public ArgumentResolverRegistrar modelAttributeSupport() { - return new ArgumentResolverRegistrar(this.configurer, null, true); + return new ArgumentResolverRegistrar(this.resolvers, null, true); } public ArgumentResolverRegistrar basic() { - return new ArgumentResolverRegistrar(this.configurer, null, false); + return new ArgumentResolverRegistrar(this.resolvers, null, 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 3a1fc17142..5bc91d9356 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,7 +16,6 @@ package org.springframework.web.reactive.result.method.annotation; -import java.util.ArrayList; import java.util.List; import java.util.function.Function; @@ -29,13 +28,6 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.ReactiveAdapterRegistry; -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.HttpMessageReader; import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.util.Assert; import org.springframework.web.bind.support.WebBindingInitializer; @@ -57,7 +49,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application private static final Log logger = LogFactory.getLog(RequestMappingHandlerAdapter.class); - private final List> messageReaders = new ArrayList<>(32); + private ServerCodecConfigurer messageCodecConfigurer; private WebBindingInitializer webBindingInitializer; @@ -72,32 +64,19 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application private ModelInitializer modelInitializer; - public RequestMappingHandlerAdapter() { - 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 HTTP message readers to de-serialize the request body with. - *

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 + *

By default this is set to {@link ServerCodecConfigurer} with defaults. */ - public void setMessageReaders(List> messageReaders) { - this.messageReaders.clear(); - this.messageReaders.addAll(messageReaders); + public void setMessageCodecConfigurer(ServerCodecConfigurer configurer) { + this.messageCodecConfigurer = configurer; } /** - * Return the configured HTTP message readers. + * Return the configurer for HTTP message readers. */ - public List> getMessageReaders() { - return this.messageReaders; + public ServerCodecConfigurer getMessageCodecConfigurer() { + return this.messageCodecConfigurer; } /** @@ -166,6 +145,10 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application @Override public void afterPropertiesSet() throws Exception { + if (this.messageCodecConfigurer == null) { + this.messageCodecConfigurer = new ServerCodecConfigurer(); + } + if (this.argumentResolverConfigurer == null) { this.argumentResolverConfigurer = new ArgumentResolverConfigurer(); } @@ -175,7 +158,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application } this.methodResolver = new ControllerMethodResolver(this.argumentResolverConfigurer, - this.messageReaders, this.reactiveAdapterRegistry, this.applicationContext); + this.messageCodecConfigurer, 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 17013136e7..1165957ade 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 @@ -68,8 +68,14 @@ 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.springframework.core.ResolvableType.*; -import static org.springframework.http.MediaType.*; +import static org.springframework.core.ResolvableType.forClass; +import static org.springframework.core.ResolvableType.forClassWithGenerics; +import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED; +import static org.springframework.http.MediaType.APPLICATION_JSON; +import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM; +import static org.springframework.http.MediaType.APPLICATION_XML; +import static org.springframework.http.MediaType.IMAGE_PNG; +import static org.springframework.http.MediaType.TEXT_PLAIN; /** * Unit tests for {@link WebFluxConfigurationSupport}. @@ -124,7 +130,7 @@ public class WebFluxConfigurationSupportTests { RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class); assertNotNull(adapter); - List> readers = adapter.getMessageReaders(); + List> readers = adapter.getMessageCodecConfigurer().getReaders(); assertEquals(9, readers.size()); assertHasMessageReader(readers, forClass(byte[].class), APPLICATION_OCTET_STREAM); @@ -158,7 +164,7 @@ public class WebFluxConfigurationSupportTests { RequestMappingHandlerAdapter adapter = context.getBean(name, RequestMappingHandlerAdapter.class); assertNotNull(adapter); - List> messageReaders = adapter.getMessageReaders(); + List> messageReaders = adapter.getMessageCodecConfigurer().getReaders(); assertEquals(2, messageReaders.size()); assertHasMessageReader(messageReaders, forClass(String.class), TEXT_PLAIN); 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 410cd12584..006b3f6a51 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.Arrays; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; @@ -32,8 +31,7 @@ import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.core.codec.ByteArrayDecoder; import org.springframework.core.codec.ByteBufferDecoder; import org.springframework.http.HttpStatus; -import org.springframework.http.codec.DecoderHttpMessageReader; -import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.codec.ServerCodecConfigurer; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -67,20 +65,20 @@ public class ControllerMethodResolverTests { @Before public void setUp() throws Exception { - ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer(); - configurer.addCustomResolver(new CustomArgumentResolver()); - configurer.addCustomResolver(new CustomSyncArgumentResolver()); + ArgumentResolverConfigurer resolvers = new ArgumentResolverConfigurer(); + resolvers.addCustomResolver(new CustomArgumentResolver()); + resolvers.addCustomResolver(new CustomSyncArgumentResolver()); - List> messageReaders = Arrays.asList( - new DecoderHttpMessageReader<>(new ByteArrayDecoder()), - new DecoderHttpMessageReader<>(new ByteBufferDecoder())); + ServerCodecConfigurer codecs = new ServerCodecConfigurer(); + codecs.customCodec().decoder(new ByteArrayDecoder()); + codecs.customCodec().decoder(new ByteBufferDecoder()); AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); applicationContext.registerBean(TestControllerAdvice.class); applicationContext.refresh(); this.methodResolver = new ControllerMethodResolver( - configurer, messageReaders, new ReactiveAdapterRegistry(), applicationContext); + resolvers, codecs, new ReactiveAdapterRegistry(), applicationContext); Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::handle).method(); this.handlerMethod = new HandlerMethod(new TestController(), method);