提交 a8162c03 编写于 作者: R Rossen Stoyanchev

Add ArgumentResolverConfigurer

Replace the List<HandlerMethodArgumentResolver> with a dedicated
configurer that currently has one method accepting custom resolver
registrations.
上级 118f33ae
......@@ -26,7 +26,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
/**
* A subclass of {@code WebFluxConfigurationSupport} that detects and delegates
......@@ -70,8 +70,8 @@ public class DelegatingWebFluxConfiguration extends WebFluxConfigurationSupport
}
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
this.configurers.addArgumentResolvers(resolvers);
protected void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
this.configurers.configureArgumentResolvers(configurer);
}
@Override
......
......@@ -16,7 +16,6 @@
package org.springframework.web.reactive.config;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -50,7 +49,7 @@ import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.handler.AbstractHandlerMapping;
import org.springframework.web.reactive.result.SimpleHandlerAdapter;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.reactive.result.method.annotation.ResponseBodyResultHandler;
......@@ -240,11 +239,9 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer());
adapter.setReactiveAdapterRegistry(webFluxAdapterRegistry());
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
addArgumentResolvers(resolvers);
if (!resolvers.isEmpty()) {
adapter.setCustomArgumentResolvers(resolvers);
}
ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer();
configureArgumentResolvers(configurer);
adapter.setArgumentResolverConfigurer(configurer);
return adapter;
}
......@@ -257,9 +254,9 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware {
}
/**
* Provide custom argument resolvers without overriding the built-in ones.
* Configure resolvers for custom controller method arguments.
*/
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
protected void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
}
/**
......
......@@ -29,6 +29,7 @@ import org.springframework.web.reactive.accept.CompositeContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
/**
* Defines callback methods to customize the configuration for Web Reactive
......@@ -80,11 +81,10 @@ public interface WebFluxConfigurer {
}
/**
* Provide custom controller method argument resolvers. Such resolvers do
* not override and will be invoked after the built-in ones.
* @param resolvers a list of resolvers to add
* Configure resolvers for custom controller method arguments.
* @param configurer to configurer to use
*/
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
default void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
}
/**
......
......@@ -28,7 +28,7 @@ import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.annotation.ArgumentResolverConfigurer;
/**
* A {@link WebFluxConfigurer} that delegates to one or more others.
......@@ -70,8 +70,8 @@ public class WebFluxConfigurerComposite implements WebFluxConfigurer {
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
this.delegates.forEach(delegate -> delegate.addArgumentResolvers(resolvers));
public void configureArgumentResolvers(ArgumentResolverConfigurer configurer) {
this.delegates.forEach(delegate -> delegate.configureArgumentResolvers(configurer));
}
@Override
......
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.web.reactive.result.method.annotation;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.springframework.util.Assert;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
/**
* Helps to configure resolvers for Controller method arguments.
*
* @author Rossen Stoyanchev
* @since 5.0
*/
public class ArgumentResolverConfigurer {
private final List<HandlerMethodArgumentResolver> customResolvers = new ArrayList<>(8);
/**
* Configure resolvers for custom controller method arguments.
* @param resolver the resolver(s) to add
*/
public void addCustomResolver(HandlerMethodArgumentResolver... resolver) {
Assert.notNull(resolver, "'resolvers' must not be null");
this.customResolvers.addAll(Arrays.asList(resolver));
}
List<HandlerMethodArgumentResolver> getCustomResolvers() {
return this.customResolvers;
}
}
......@@ -17,6 +17,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;
......@@ -95,34 +96,36 @@ class ControllerMethodResolver {
new LinkedHashMap<>(64);
ControllerMethodResolver(List<HandlerMethodArgumentResolver> customResolvers,
ControllerMethodResolver(ArgumentResolverConfigurer argumentResolverConfigurer,
List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry reactiveRegistry,
ConfigurableApplicationContext applicationContext) {
Assert.notNull(customResolvers, "'customResolvers' should not be null");
Assert.notNull(argumentResolverConfigurer, "ArgumentResolverConfigurer is required");
Assert.notNull(reactiveRegistry, "ReactiveAdapterRegistry is required");
Assert.notNull(applicationContext, "ConfigurableApplicationContext is required");
ResolverRegistrar registrar = ResolverRegistrar.customResolvers(customResolvers).basic();
ArgumentResolverRegistrar registrar;
registrar= ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).basic();
addResolversTo(registrar, reactiveRegistry, applicationContext);
this.initBinderResolvers = registrar.getSyncResolvers();
registrar = ResolverRegistrar.customResolvers(customResolvers).modelAttributeSupport();
registrar = ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).modelAttributeSupport();
addResolversTo(registrar, reactiveRegistry, applicationContext);
this.modelAttributeResolvers = registrar.getResolvers();
registrar = ResolverRegistrar.customResolvers(customResolvers).fullSupport(messageReaders);
registrar = ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).fullSupport(messageReaders);
addResolversTo(registrar, reactiveRegistry, applicationContext);
this.requestMappingResolvers = registrar.getResolvers();
registrar = ResolverRegistrar.customResolvers(customResolvers).basic();
registrar = ArgumentResolverRegistrar.configurer(argumentResolverConfigurer).basic();
addResolversTo(registrar, reactiveRegistry, applicationContext);
this.exceptionHandlerResolvers = registrar.getResolvers();
initControllerAdviceCaches(applicationContext);
}
private void addResolversTo(ResolverRegistrar registrar,
private void addResolversTo(ArgumentResolverRegistrar registrar,
ReactiveAdapterRegistry reactiveRegistry, ConfigurableApplicationContext context) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
......@@ -319,7 +322,7 @@ class ControllerMethodResolver {
(AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null);
private static class ResolverRegistrar {
private static class ArgumentResolverRegistrar {
private final List<HandlerMethodArgumentResolver> customResolvers;
......@@ -330,10 +333,10 @@ class ControllerMethodResolver {
private final List<HandlerMethodArgumentResolver> result = new ArrayList<>();
private ResolverRegistrar(List<HandlerMethodArgumentResolver> customResolvers,
private ArgumentResolverRegistrar(ArgumentResolverConfigurer configurer,
List<HttpMessageReader<?>> messageReaders, boolean modelAttribute) {
this.customResolvers = new ArrayList<>(customResolvers);
this.customResolvers = configurer.getCustomResolvers();
this.messageReaders = messageReaders != null ? new ArrayList<>(messageReaders) : null;
this.modelAttributeSupported = modelAttribute;
}
......@@ -372,32 +375,32 @@ class ControllerMethodResolver {
}
public static Builder customResolvers(List<HandlerMethodArgumentResolver> customResolvers) {
return new Builder(customResolvers);
public static Builder configurer(ArgumentResolverConfigurer configurer) {
return new Builder(configurer);
}
public static class Builder {
private final List<HandlerMethodArgumentResolver> customResolvers;
private final ArgumentResolverConfigurer configurer;
public Builder(List<HandlerMethodArgumentResolver> customResolvers) {
this.customResolvers = new ArrayList<>(customResolvers);
public Builder(ArgumentResolverConfigurer configurer) {
this.configurer = configurer;
}
public ResolverRegistrar fullSupport(List<HttpMessageReader<?>> readers) {
public ArgumentResolverRegistrar fullSupport(List<HttpMessageReader<?>> readers) {
Assert.notEmpty(readers, "No message readers");
return new ResolverRegistrar(this.customResolvers, readers, true);
return new ArgumentResolverRegistrar(this.configurer, readers, true);
}
public ResolverRegistrar modelAttributeSupport() {
return new ResolverRegistrar(this.customResolvers, null, true);
public ArgumentResolverRegistrar modelAttributeSupport() {
return new ArgumentResolverRegistrar(this.configurer, null, true);
}
public ResolverRegistrar basic() {
return new ResolverRegistrar(this.customResolvers, null, false);
public ArgumentResolverRegistrar basic() {
return new ArgumentResolverRegistrar(this.configurer, null, false);
}
}
......
......@@ -25,7 +25,6 @@ import org.apache.commons.logging.LogFactory;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
......@@ -44,7 +43,6 @@ import org.springframework.web.method.HandlerMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.reactive.HandlerAdapter;
import org.springframework.web.reactive.HandlerResult;
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.InvocableHandlerMethod;
import org.springframework.web.server.ServerWebExchange;
......@@ -63,9 +61,9 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
private WebBindingInitializer webBindingInitializer;
private ReactiveAdapterRegistry reactiveAdapterRegistry = new ReactiveAdapterRegistry();
private ArgumentResolverConfigurer argumentResolverConfigurer;
private final List<HandlerMethodArgumentResolver> customArgumentResolvers = new ArrayList<>(8);
private ReactiveAdapterRegistry reactiveAdapterRegistry;
private ConfigurableApplicationContext applicationContext;
......@@ -118,34 +116,34 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
}
/**
* Configure the registry for adapting various reactive types.
* <p>By default this is an instance of {@link ReactiveAdapterRegistry} with
* default settings.
* Configure resolvers for controller method arguments.
*/
public void setReactiveAdapterRegistry(ReactiveAdapterRegistry registry) {
this.reactiveAdapterRegistry = registry;
public void setArgumentResolverConfigurer(ArgumentResolverConfigurer configurer) {
Assert.notNull(configurer, "ArgumentResolverConfigurer is required");
this.argumentResolverConfigurer = configurer;
}
/**
* Return the configured registry for adapting reactive types.
* Return the configured resolvers for controller method arguments.
*/
public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
return this.reactiveAdapterRegistry;
public ArgumentResolverConfigurer getArgumentResolverConfigurer() {
return this.argumentResolverConfigurer;
}
/**
* Configure resolvers for custom controller method arguments.
* Configure the registry for adapting various reactive types.
* <p>By default this is an instance of {@link ReactiveAdapterRegistry} with
* default settings.
*/
public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
this.customArgumentResolvers.clear();
this.customArgumentResolvers.addAll(resolvers);
public void setReactiveAdapterRegistry(ReactiveAdapterRegistry registry) {
this.reactiveAdapterRegistry = registry;
}
/**
* Return the configured custom argument resolvers.
* Return the configured registry for adapting reactive types.
*/
public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {
return this.customArgumentResolvers;
public ReactiveAdapterRegistry getReactiveAdapterRegistry() {
return this.reactiveAdapterRegistry;
}
/**
......@@ -164,18 +162,22 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
return this.applicationContext;
}
public ConfigurableBeanFactory getBeanFactory() {
return this.applicationContext.getBeanFactory();
}
@Override
public void afterPropertiesSet() throws Exception {
this.methodResolver = new ControllerMethodResolver(getCustomArgumentResolvers(),
getMessageReaders(), getReactiveAdapterRegistry(), getApplicationContext());
if (this.argumentResolverConfigurer == null) {
this.argumentResolverConfigurer = new ArgumentResolverConfigurer();
}
if (this.reactiveAdapterRegistry == null) {
this.reactiveAdapterRegistry = new ReactiveAdapterRegistry();
}
this.methodResolver = new ControllerMethodResolver(this.argumentResolverConfigurer,
this.messageReaders, this.reactiveAdapterRegistry, this.applicationContext);
this.modelInitializer = new ModelInitializer(getReactiveAdapterRegistry());
this.modelInitializer = new ModelInitializer(this.reactiveAdapterRegistry);
}
......
......@@ -100,7 +100,7 @@ public class DelegatingWebFluxConfigurationTests {
verify(webFluxConfigurer).getValidator();
verify(webFluxConfigurer).getMessageCodesResolver();
verify(webFluxConfigurer).addFormatters(formatterRegistry.capture());
verify(webFluxConfigurer).addArgumentResolvers(any());
verify(webFluxConfigurer).configureArgumentResolvers(any());
assertSame(formatterRegistry.getValue(), initializerConversionService);
assertEquals(9, codecsConfigurer.getValue().getReaders().size());
......
......@@ -67,8 +67,9 @@ public class ControllerMethodResolverTests {
@Before
public void setUp() throws Exception {
List<HandlerMethodArgumentResolver> customResolvers =
Arrays.asList(new CustomArgumentResolver(), new CustomSyncArgumentResolver());
ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer();
configurer.addCustomResolver(new CustomArgumentResolver());
configurer.addCustomResolver(new CustomSyncArgumentResolver());
List<HttpMessageReader<?>> messageReaders = Arrays.asList(
new DecoderHttpMessageReader<>(new ByteArrayDecoder()),
......@@ -79,7 +80,7 @@ public class ControllerMethodResolverTests {
applicationContext.refresh();
this.methodResolver = new ControllerMethodResolver(
customResolvers, messageReaders, new ReactiveAdapterRegistry(), applicationContext);
configurer, messageReaders, new ReactiveAdapterRegistry(), applicationContext);
Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::handle).method();
this.handlerMethod = new HandlerMethod(new TestController(), method);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册