Browse Source

Polish: simplify ControllerMethodResolver initialization

pull/1837/head
Rossen Stoyanchev 8 years ago
parent
commit
ab0b0b31fd
  1. 220
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java
  2. 2
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
  3. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolverTests.java
  4. 2
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelInitializerTests.java

220
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolver.java

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2017 the original author or authors. * Copyright 2002-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,8 +24,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@ -40,7 +38,6 @@ import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.codec.HttpMessageReader;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.ModelAttribute;
@ -53,7 +50,7 @@ import org.springframework.web.reactive.result.method.InvocableHandlerMethod;
import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver; import org.springframework.web.reactive.result.method.SyncHandlerMethodArgumentResolver;
import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod; import org.springframework.web.reactive.result.method.SyncInvocableHandlerMethod;
import static org.springframework.core.MethodIntrospector.selectMethods; import static org.springframework.core.MethodIntrospector.*;
/** /**
* Package-private class to assist {@link RequestMappingHandlerAdapter} with * Package-private class to assist {@link RequestMappingHandlerAdapter} with
@ -102,81 +99,112 @@ class ControllerMethodResolver {
private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64); private final Map<Class<?>, SessionAttributesHandler> sessionAttributesHandlerCache = new ConcurrentHashMap<>(64);
ControllerMethodResolver(ArgumentResolverConfigurer argumentResolvers, ControllerMethodResolver(ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry,
List<HttpMessageReader<?>> messageReaders, ReactiveAdapterRegistry reactiveRegistry, ConfigurableApplicationContext context, List<HttpMessageReader<?>> readers) {
ConfigurableApplicationContext context) {
Assert.notNull(argumentResolvers, "ArgumentResolverConfigurer is required"); Assert.notNull(customResolvers, "ArgumentResolverConfigurer is required");
Assert.notNull(messageReaders, "'messageReaders' is required"); Assert.notNull(readers, "'messageReaders' is required");
Assert.notNull(reactiveRegistry, "ReactiveAdapterRegistry is required"); Assert.notNull(reactiveRegistry, "ReactiveAdapterRegistry is required");
Assert.notNull(context, "ApplicationContext is required"); Assert.notNull(context, "ApplicationContext is required");
ArgumentResolverRegistrar registrar; this.initBinderResolvers = initBinderResolvers(customResolvers, reactiveRegistry, context);
this.modelAttributeResolvers = modelMethodResolvers(customResolvers, reactiveRegistry, context);
this.requestMappingResolvers = requestMappingResolvers(customResolvers, reactiveRegistry, context, readers);
this.exceptionHandlerResolvers = exceptionHandlerResolvers(customResolvers, reactiveRegistry, context);
this.reactiveAdapterRegistry = reactiveRegistry;
registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).basic(); initControllerAdviceCaches(context);
addResolversTo(registrar, reactiveRegistry, context); }
this.initBinderResolvers = registrar.getSyncResolvers();
registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).modelAttributeSupport(); private List<SyncHandlerMethodArgumentResolver> initBinderResolvers(
addResolversTo(registrar, reactiveRegistry, context); ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry,
this.modelAttributeResolvers = registrar.getResolvers(); ConfigurableApplicationContext context) {
registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).fullSupport(messageReaders); return initResolvers(customResolvers, reactiveRegistry, context, false, Collections.emptyList()).stream()
addResolversTo(registrar, reactiveRegistry, context); .filter(resolver -> resolver instanceof SyncHandlerMethodArgumentResolver)
this.requestMappingResolvers = registrar.getResolvers(); .map(resolver -> (SyncHandlerMethodArgumentResolver) resolver)
.collect(Collectors.toList());
}
registrar = ArgumentResolverRegistrar.configurer(argumentResolvers).basic(); private static List<HandlerMethodArgumentResolver> modelMethodResolvers(
addResolversTo(registrar, reactiveRegistry, context); ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry,
this.exceptionHandlerResolvers = registrar.getResolvers(); ConfigurableApplicationContext context) {
this.reactiveAdapterRegistry = reactiveRegistry; return initResolvers(customResolvers, reactiveRegistry, context, true, Collections.emptyList());
}
initControllerAdviceCaches(context); private static List<HandlerMethodArgumentResolver> requestMappingResolvers(
ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry,
ConfigurableApplicationContext context, List<HttpMessageReader<?>> readers) {
return initResolvers(customResolvers, reactiveRegistry, context, true, readers);
}
private static List<HandlerMethodArgumentResolver> exceptionHandlerResolvers(
ArgumentResolverConfigurer customResolvers, ReactiveAdapterRegistry reactiveRegistry,
ConfigurableApplicationContext context) {
return initResolvers(customResolvers, reactiveRegistry, context, false, Collections.emptyList());
} }
private void addResolversTo(ArgumentResolverRegistrar registrar, private static List<HandlerMethodArgumentResolver> initResolvers(ArgumentResolverConfigurer customResolvers,
ReactiveAdapterRegistry reactiveRegistry, ConfigurableApplicationContext context) { ReactiveAdapterRegistry reactiveRegistry, ConfigurableApplicationContext context,
boolean supportDataBinding, List<HttpMessageReader<?>> readers) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
boolean requestMappingMethod = !readers.isEmpty() && supportDataBinding;
// Annotation-based... // Annotation-based...
registrar.add(new RequestParamMethodArgumentResolver(beanFactory, reactiveRegistry, false)); List<HandlerMethodArgumentResolver> result = new ArrayList<>();
registrar.add(new RequestParamMapMethodArgumentResolver(reactiveRegistry)); result.add(new RequestParamMethodArgumentResolver(beanFactory, reactiveRegistry, false));
registrar.add(new PathVariableMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new RequestParamMapMethodArgumentResolver(reactiveRegistry));
registrar.add(new PathVariableMapMethodArgumentResolver(reactiveRegistry)); result.add(new PathVariableMethodArgumentResolver(beanFactory, reactiveRegistry));
registrar.add(new MatrixVariableMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new PathVariableMapMethodArgumentResolver(reactiveRegistry));
registrar.add(new MatrixVariableMapMethodArgumentResolver(reactiveRegistry)); result.add(new MatrixVariableMethodArgumentResolver(beanFactory, reactiveRegistry));
registrar.addIfRequestBody(readers -> new RequestBodyArgumentResolver(readers, reactiveRegistry)); result.add(new MatrixVariableMapMethodArgumentResolver(reactiveRegistry));
registrar.addIfRequestBody(readers -> new RequestPartMethodArgumentResolver(readers, reactiveRegistry)); if (!readers.isEmpty()) {
registrar.addIfModelAttribute(() -> new ModelAttributeMethodArgumentResolver(reactiveRegistry, false)); result.add(new RequestBodyArgumentResolver(readers, reactiveRegistry));
registrar.add(new RequestHeaderMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new RequestPartMethodArgumentResolver(readers, reactiveRegistry));
registrar.add(new RequestHeaderMapMethodArgumentResolver(reactiveRegistry)); }
registrar.add(new CookieValueMethodArgumentResolver(beanFactory, reactiveRegistry)); if (supportDataBinding) {
registrar.add(new ExpressionValueMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new ModelAttributeMethodArgumentResolver(reactiveRegistry, false));
registrar.add(new SessionAttributeMethodArgumentResolver(beanFactory, reactiveRegistry)); }
registrar.add(new RequestAttributeMethodArgumentResolver(beanFactory, reactiveRegistry)); result.add(new RequestHeaderMethodArgumentResolver(beanFactory, reactiveRegistry));
result.add(new RequestHeaderMapMethodArgumentResolver(reactiveRegistry));
result.add(new CookieValueMethodArgumentResolver(beanFactory, reactiveRegistry));
result.add(new ExpressionValueMethodArgumentResolver(beanFactory, reactiveRegistry));
result.add(new SessionAttributeMethodArgumentResolver(beanFactory, reactiveRegistry));
result.add(new RequestAttributeMethodArgumentResolver(beanFactory, reactiveRegistry));
// Type-based... // Type-based...
registrar.addIfRequestBody(readers -> new HttpEntityArgumentResolver(readers, reactiveRegistry)); if (!readers.isEmpty()) {
registrar.add(new ModelArgumentResolver(reactiveRegistry)); result.add(new HttpEntityArgumentResolver(readers, reactiveRegistry));
registrar.addIfModelAttribute(() -> new ErrorsMethodArgumentResolver(reactiveRegistry)); }
registrar.add(new ServerWebExchangeArgumentResolver(reactiveRegistry)); result.add(new ModelArgumentResolver(reactiveRegistry));
registrar.add(new PrincipalArgumentResolver(reactiveRegistry)); if (supportDataBinding) {
registrar.addIfRequestBody(readers -> new SessionStatusMethodArgumentResolver()); result.add(new ErrorsMethodArgumentResolver(reactiveRegistry));
registrar.add(new WebSessionArgumentResolver(reactiveRegistry)); }
result.add(new ServerWebExchangeArgumentResolver(reactiveRegistry));
result.add(new PrincipalArgumentResolver(reactiveRegistry));
if (requestMappingMethod) {
result.add(new SessionStatusMethodArgumentResolver());
}
result.add(new WebSessionArgumentResolver(reactiveRegistry));
// Custom... // Custom...
registrar.addCustomResolvers(); result.addAll(customResolvers.getCustomResolvers());
// Catch-all... // Catch-all...
registrar.add(new RequestParamMethodArgumentResolver(beanFactory, reactiveRegistry, true)); result.add(new RequestParamMethodArgumentResolver(beanFactory, reactiveRegistry, true));
registrar.addIfModelAttribute(() -> new ModelAttributeMethodArgumentResolver(reactiveRegistry, true)); if (supportDataBinding) {
result.add(new ModelAttributeMethodArgumentResolver(reactiveRegistry, true));
}
return result;
} }
private void initControllerAdviceCaches(@Nullable ApplicationContext applicationContext) { private void initControllerAdviceCaches(ApplicationContext applicationContext) {
if (applicationContext == null) {
return;
}
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info("Looking for @ControllerAdvice: " + applicationContext); logger.info("Looking for @ControllerAdvice: " + applicationContext);
} }
@ -354,84 +382,4 @@ class ControllerMethodResolver {
(AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) && (AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) &&
(AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null); (AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null);
private static class ArgumentResolverRegistrar {
private final List<HandlerMethodArgumentResolver> customResolvers;
private final List<HttpMessageReader<?>> messageReaders;
private final boolean modelAttributeSupported;
private final List<HandlerMethodArgumentResolver> result = new ArrayList<>();
private ArgumentResolverRegistrar(ArgumentResolverConfigurer resolvers,
List<HttpMessageReader<?>> messageReaders, boolean modelAttribute) {
this.customResolvers = resolvers.getCustomResolvers();
this.messageReaders = messageReaders;
this.modelAttributeSupported = modelAttribute;
}
public void add(HandlerMethodArgumentResolver resolver) {
this.result.add(resolver);
}
public void addIfRequestBody(Function<List<HttpMessageReader<?>>, HandlerMethodArgumentResolver> function) {
if (!CollectionUtils.isEmpty(this.messageReaders)) {
add(function.apply(this.messageReaders));
}
}
public void addIfModelAttribute(Supplier<HandlerMethodArgumentResolver> supplier) {
if (this.modelAttributeSupported) {
add(supplier.get());
}
}
public void addCustomResolvers() {
this.customResolvers.forEach(this::add);
}
public List<HandlerMethodArgumentResolver> getResolvers() {
return this.result;
}
public List<SyncHandlerMethodArgumentResolver> getSyncResolvers() {
return this.result.stream()
.filter(resolver -> resolver instanceof SyncHandlerMethodArgumentResolver)
.map(resolver -> (SyncHandlerMethodArgumentResolver) resolver)
.collect(Collectors.toList());
}
public static Builder configurer(ArgumentResolverConfigurer configurer) {
return new Builder(configurer);
}
public static class Builder {
private final ArgumentResolverConfigurer resolvers;
public Builder(ArgumentResolverConfigurer configurer) {
this.resolvers = configurer;
}
public ArgumentResolverRegistrar fullSupport(List<HttpMessageReader<?>> httpMessageReaders) {
return new ArgumentResolverRegistrar(this.resolvers, httpMessageReaders, true);
}
public ArgumentResolverRegistrar modelAttributeSupport() {
return new ArgumentResolverRegistrar(this.resolvers, Collections.emptyList(), true);
}
public ArgumentResolverRegistrar basic() {
return new ArgumentResolverRegistrar(this.resolvers, Collections.emptyList(), false);
}
}
}
} }

2
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java

@ -169,7 +169,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, Application
} }
this.methodResolver = new ControllerMethodResolver(this.argumentResolverConfigurer, this.methodResolver = new ControllerMethodResolver(this.argumentResolverConfigurer,
this.messageReaders, this.reactiveAdapterRegistry, this.applicationContext); this.reactiveAdapterRegistry, this.applicationContext, this.messageReaders);
this.modelInitializer = new ModelInitializer(this.methodResolver, this.reactiveAdapterRegistry); this.modelInitializer = new ModelInitializer(this.methodResolver, this.reactiveAdapterRegistry);
} }

2
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ControllerMethodResolverTests.java

@ -76,7 +76,7 @@ public class ControllerMethodResolverTests {
applicationContext.refresh(); applicationContext.refresh();
this.methodResolver = new ControllerMethodResolver( this.methodResolver = new ControllerMethodResolver(
resolvers, codecs.getReaders(), ReactiveAdapterRegistry.getSharedInstance(), applicationContext); resolvers, ReactiveAdapterRegistry.getSharedInstance(), applicationContext, codecs.getReaders());
Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::handle).method(); Method method = ResolvableMethod.on(TestController.class).mockCall(TestController::handle).method();
this.handlerMethod = new HandlerMethod(new TestController(), method); this.handlerMethod = new HandlerMethod(new TestController(), method);

2
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/ModelInitializerTests.java

@ -79,7 +79,7 @@ public class ModelInitializerTests {
resolverConfigurer.addCustomResolver(new ModelArgumentResolver(adapterRegistry)); resolverConfigurer.addCustomResolver(new ModelArgumentResolver(adapterRegistry));
ControllerMethodResolver methodResolver = new ControllerMethodResolver( ControllerMethodResolver methodResolver = new ControllerMethodResolver(
resolverConfigurer, Collections.emptyList(), adapterRegistry, new StaticApplicationContext()); resolverConfigurer, adapterRegistry, new StaticApplicationContext(), Collections.emptyList());
this.modelInitializer = new ModelInitializer(methodResolver, adapterRegistry); this.modelInitializer = new ModelInitializer(methodResolver, adapterRegistry);
} }

Loading…
Cancel
Save