ServerCodecConfigurer as input in HandlerAdapter
The ServerCodecConfigurer is now passed all the way into the RequestMappingHandlerAdapter which automatically enables the same defaults even without the Java config and provides extra flexibility in passing message codec configuration for the future.
This commit is contained in:
@@ -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());
|
||||
|
||||
|
||||
@@ -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<HttpMessageReader<?>> 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<HandlerMethodArgumentResolver> result = new ArrayList<>();
|
||||
|
||||
|
||||
private ArgumentResolverRegistrar(ArgumentResolverConfigurer configurer,
|
||||
List<HttpMessageReader<?>> 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<HttpMessageReader<?>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<HttpMessageReader<?>> 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.
|
||||
* <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
|
||||
* <p>By default this is set to {@link ServerCodecConfigurer} with defaults.
|
||||
*/
|
||||
public void setMessageReaders(List<HttpMessageReader<?>> 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<HttpMessageReader<?>> 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);
|
||||
}
|
||||
|
||||
@@ -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<HttpMessageReader<?>> readers = adapter.getMessageReaders();
|
||||
List<HttpMessageReader<?>> 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<HttpMessageReader<?>> messageReaders = adapter.getMessageReaders();
|
||||
List<HttpMessageReader<?>> messageReaders = adapter.getMessageCodecConfigurer().getReaders();
|
||||
assertEquals(2, messageReaders.size());
|
||||
|
||||
assertHasMessageReader(messageReaders, forClass(String.class), TEXT_PLAIN);
|
||||
|
||||
@@ -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<HttpMessageReader<?>> 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);
|
||||
|
||||
Reference in New Issue
Block a user