Add support to reference external HandlerMethodArgumentResolver beans which might contain already configured instances (e.g. through a 3rd-party namespace handler).
Users can not mix and match between "inner bean" argument resolver and "external bean" argument resolver. This commit only focuses only on argument-resolver, while the support could be extended to return value handlers as well. Issue: SPR-11927
This commit is contained in:
parent
a4484bb767
commit
19760f9eb9
|
@ -19,14 +19,14 @@ package org.springframework.web.servlet.config;
|
|||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
|
@ -44,11 +44,13 @@ import org.springframework.http.converter.ResourceHttpMessageConverter;
|
|||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.http.converter.feed.AtomFeedHttpMessageConverter;
|
||||
import org.springframework.http.converter.feed.RssChannelHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
|
||||
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.springframework.web.HttpRequestHandler;
|
||||
import org.springframework.web.accept.ContentNegotiationManager;
|
||||
|
@ -69,6 +71,7 @@ import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
|
|||
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
@ -138,6 +141,7 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
|
|||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @author Agim Emruli
|
||||
* @since 3.0
|
||||
*/
|
||||
class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
||||
|
@ -468,7 +472,10 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
|
||||
if (resolversElement != null) {
|
||||
ManagedList<BeanDefinitionHolder> argumentResolvers = extractBeanSubElements(resolversElement, parserContext);
|
||||
return wrapWebArgumentResolverBeanDefs(argumentResolvers, parserContext);
|
||||
ManagedList<BeanMetadataElement> customAndReferencedResolvers = new ManagedList<BeanMetadataElement>();
|
||||
customAndReferencedResolvers.addAll(wrapWebArgumentResolverBeanDefs(argumentResolvers, parserContext));
|
||||
customAndReferencedResolvers.addAll(extractBeanRefSubElements(resolversElement, parserContext));
|
||||
return customAndReferencedResolvers;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -540,6 +547,25 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
|
|||
return list;
|
||||
}
|
||||
|
||||
private ManagedList<BeanReference> extractBeanRefSubElements(Element parentElement, ParserContext parserContext){
|
||||
ManagedList<BeanReference> list = new ManagedList<BeanReference>();
|
||||
list.setSource(parserContext.extractSource(parentElement));
|
||||
for (Element refElement : DomUtils.getChildElementsByTagName(parentElement, "ref")) {
|
||||
BeanReference reference;
|
||||
if (StringUtils.hasText("bean")) {
|
||||
reference = new RuntimeBeanReference(refElement.getAttribute("bean"),false);
|
||||
list.add(reference);
|
||||
}else if(StringUtils.hasText("parent")){
|
||||
reference = new RuntimeBeanReference(refElement.getAttribute("parent"),true);
|
||||
list.add(reference);
|
||||
}else{
|
||||
parserContext.getReaderContext().error("'bean' or 'parent' attribute is required for <ref> element",
|
||||
parserContext.extractSource(parentElement));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private ManagedList<BeanDefinitionHolder> wrapWebArgumentResolverBeanDefs(
|
||||
List<BeanDefinitionHolder> beanDefs, ParserContext parserContext) {
|
||||
|
||||
|
|
|
@ -127,15 +127,28 @@
|
|||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="beans:bean" minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:choice minOccurs="1" maxOccurs="unbounded">
|
||||
<xsd:element ref="beans:bean" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
The HandlerMethodArgumentResolver (or WebArgumentResolver for backwards compatibility) bean definition.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
<xsd:element ref="beans:ref" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
A reference to a HandlerMethodArgumentResolver bean definition. Expects a HandlerMethodArgumentResolver instance,
|
||||
WebArgumentResolver instances has to be wrapped with a ServletWebArgumentResolverAdapter
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="java:org.springframework.web.method.support.HandlerMethodArgumentResolver" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="return-value-handlers" minOccurs="0">
|
||||
|
|
|
@ -38,9 +38,9 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|||
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ServletWebArgumentResolverAdapter;
|
||||
|
@ -52,6 +52,7 @@ import static org.junit.Assert.*;
|
|||
* Test fixture for the configuration in mvc-config-annotation-driven.xml.
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Brian Clozel
|
||||
* @author Agim Emruli
|
||||
*/
|
||||
public class AnnotationDrivenBeanDefinitionParserTests {
|
||||
|
||||
|
@ -121,6 +122,21 @@ public class AnnotationDrivenBeanDefinitionParserTests {
|
|||
assertTrue(resolvers.get(1) instanceof TestHandlerMethodArgumentResolver);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testArgumentResolversWithReference() {
|
||||
loadBeanDefinitions("mvc-config-argument-resolvers-references.xml");
|
||||
RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class);
|
||||
assertNotNull(adapter);
|
||||
Object value = new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
|
||||
assertNotNull(value);
|
||||
assertTrue(value instanceof List);
|
||||
List<HandlerMethodArgumentResolver> resolvers = (List<HandlerMethodArgumentResolver>) value;
|
||||
assertEquals(2, resolvers.size());
|
||||
assertTrue(resolvers.get(0) instanceof ServletWebArgumentResolverAdapter);
|
||||
assertTrue(resolvers.get(1) instanceof TestHandlerMethodArgumentResolver);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testReturnValueHandlers() {
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:mvc="http://www.springframework.org/schema/mvc"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">
|
||||
|
||||
<mvc:annotation-driven>
|
||||
<mvc:argument-resolvers>
|
||||
<bean class="org.springframework.web.servlet.config.TestWebArgumentResolver"/>
|
||||
<ref bean="customArgumentResolver" />
|
||||
</mvc:argument-resolvers>
|
||||
</mvc:annotation-driven>
|
||||
|
||||
<bean id="customArgumentResolver" class="org.springframework.web.servlet.config.TestHandlerMethodArgumentResolver"/>
|
||||
|
||||
</beans>
|
Loading…
Reference in New Issue