Browse Source

Support for custom argument resolvers

pull/1111/head
Rossen Stoyanchev 9 years ago
parent
commit
b45a48d0fc
  1. 104
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerAdapter.java
  2. 8
      spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java

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

@ -50,6 +50,8 @@ import org.springframework.web.server.ServerWebExchange;
/** /**
* Supports the invocation of {@code @RequestMapping} methods.
*
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
*/ */
public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactoryAware, InitializingBean { public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactoryAware, InitializingBean {
@ -57,9 +59,11 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
private static Log logger = LogFactory.getLog(RequestMappingHandlerAdapter.class); private static Log logger = LogFactory.getLog(RequestMappingHandlerAdapter.class);
private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>(); private List<HandlerMethodArgumentResolver> customArgumentResolvers;
private List<HandlerMethodArgumentResolver> argumentResolvers;
private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); private final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(10);
private ConversionService conversionService = new DefaultFormattingConversionService(); private ConversionService conversionService = new DefaultFormattingConversionService();
@ -75,13 +79,26 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
} }
/**
* Provide custom argument resolvers without overriding the built-in ones.
*/
public void setCustomArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
this.customArgumentResolvers = argumentResolvers;
}
/**
* Return the custom argument resolvers.
*/
public List<HandlerMethodArgumentResolver> getCustomArgumentResolvers() {
return this.customArgumentResolvers;
}
/** /**
* Configure the complete list of supported argument types thus overriding * Configure the complete list of supported argument types thus overriding
* the resolvers that would otherwise be configured by default. * the resolvers that would otherwise be configured by default.
*/ */
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { public void setArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
this.argumentResolvers.clear(); this.argumentResolvers = new ArrayList<>(resolvers);
this.argumentResolvers.addAll(resolvers);
} }
/** /**
@ -91,22 +108,35 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
return this.argumentResolvers; return this.argumentResolvers;
} }
/**
* Configure message converters to read the request body with.
*/
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) { public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters.clear(); this.messageConverters.clear();
this.messageConverters.addAll(messageConverters); this.messageConverters.addAll(messageConverters);
} }
/** /**
* Provide the message converters to use for argument resolution. * Return the configured message converters.
*/ */
public List<HttpMessageConverter<?>> getMessageConverters() { public List<HttpMessageConverter<?>> getMessageConverters() {
return this.messageConverters; return this.messageConverters;
} }
/**
* Configure a ConversionService for type conversion of controller method
* arguments as well as for converting from different async types to
* {@code Flux} and {@code Mono}.
*
* TODO: this may be replaced by DataBinder
*/
public void setConversionService(ConversionService conversionService) { public void setConversionService(ConversionService conversionService) {
this.conversionService = conversionService; this.conversionService = conversionService;
} }
/**
* Return the configured ConversionService.
*/
public ConversionService getConversionService() { public ConversionService getConversionService() {
return this.conversionService; return this.conversionService;
} }
@ -123,43 +153,47 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
} }
public ConfigurableBeanFactory getBeanFactory() { public ConfigurableBeanFactory getBeanFactory() {
return beanFactory; return this.beanFactory;
} }
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
if (ObjectUtils.isEmpty(this.argumentResolvers)) { if (this.argumentResolvers == null) {
this.argumentResolvers = initArgumentResolvers();
// List<HttpMessageConverter<?>> converters = Arrays.asList(
// new CodecHttpMessageConverter<ByteBuffer>(new ByteBufferEncoder(), new ByteBufferDecoder()),
// new CodecHttpMessageConverter<String>(new StringEncoder(), new StringDecoder()),
// new CodecHttpMessageConverter<Object>(new Jaxb2Encoder(), new Jaxb2Decoder()),
// new CodecHttpMessageConverter<Object>(new JacksonJsonEncoder(),
// new JacksonJsonDecoder(new JsonObjectDecoder())));
// Annotation-based argument resolution
ConversionService cs = getConversionService();
this.argumentResolvers.add(new RequestParamMethodArgumentResolver(cs, getBeanFactory(), false));
this.argumentResolvers.add(new RequestParamMapMethodArgumentResolver());
this.argumentResolvers.add(new PathVariableMethodArgumentResolver(cs, getBeanFactory()));
this.argumentResolvers.add(new PathVariableMapMethodArgumentResolver());
this.argumentResolvers.add(new RequestBodyArgumentResolver(getMessageConverters(), cs));
this.argumentResolvers.add(new RequestHeaderMethodArgumentResolver(cs, getBeanFactory()));
this.argumentResolvers.add(new RequestHeaderMapMethodArgumentResolver());
this.argumentResolvers.add(new CookieValueMethodArgumentResolver(cs, getBeanFactory()));
this.argumentResolvers.add(new ExpressionValueMethodArgumentResolver(cs, getBeanFactory()));
this.argumentResolvers.add(new SessionAttributeMethodArgumentResolver(cs, getBeanFactory()));
this.argumentResolvers.add(new RequestAttributeMethodArgumentResolver(cs , getBeanFactory()));
// Type-based argument resolution
this.argumentResolvers.add(new ModelArgumentResolver());
// Catch-all
this.argumentResolvers.add(new RequestParamMethodArgumentResolver(cs, getBeanFactory(), true));
} }
} }
protected List<HandlerMethodArgumentResolver> initArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>();
// Annotation-based argument resolution
ConversionService cs = getConversionService();
resolvers.add(new RequestParamMethodArgumentResolver(cs, getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new RequestBodyArgumentResolver(getMessageConverters(), cs));
resolvers.add(new RequestHeaderMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new CookieValueMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver(cs, getBeanFactory()));
resolvers.add(new RequestAttributeMethodArgumentResolver(cs , getBeanFactory()));
// Type-based argument resolution
resolvers.add(new ModelArgumentResolver());
// Custom resolvers
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new RequestParamMethodArgumentResolver(cs, getBeanFactory(), true));
return resolvers;
}
@Override @Override
public boolean supports(Object handler) { public boolean supports(Object handler) {
return HandlerMethod.class.equals(handler.getClass()); return HandlerMethod.class.equals(handler.getClass());
@ -169,7 +203,7 @@ public class RequestMappingHandlerAdapter implements HandlerAdapter, BeanFactory
public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) { public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
HandlerMethod handlerMethod = (HandlerMethod) handler; HandlerMethod handlerMethod = (HandlerMethod) handler;
InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod); InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod);
invocable.setHandlerMethodArgumentResolvers(this.argumentResolvers); invocable.setHandlerMethodArgumentResolvers(getArgumentResolvers());
ModelMap model = new ExtendedModelMap(); ModelMap model = new ExtendedModelMap();
return invocable.invokeForRequest(exchange, model) return invocable.invokeForRequest(exchange, model)
.map(result -> result.setExceptionHandler(ex -> handleException(ex, handlerMethod, exchange))) .map(result -> result.setExceptionHandler(ex -> handleException(ex, handlerMethod, exchange)))

8
spring-web-reactive/src/main/java/org/springframework/web/reactive/result/method/annotation/ResponseBodyResultHandler.java

@ -78,6 +78,14 @@ public class ResponseBodyResultHandler extends ContentNegotiatingResultHandlerSu
this(converters, conversionService, new HeaderContentTypeResolver()); this(converters, conversionService, new HeaderContentTypeResolver());
} }
/**
* Return the configured message converters.
*/
public List<HttpMessageConverter<?>> getMessageConverters() {
return this.messageConverters;
}
/** /**
* Constructor with message converters, a {@code ConversionService}, and a * Constructor with message converters, a {@code ConversionService}, and a
* {@code RequestedContentTypeResolver}. * {@code RequestedContentTypeResolver}.

Loading…
Cancel
Save