Support <ref> for arg resolvers return value handlers

Issue: SPR-11927
This commit is contained in:
Rossen Stoyanchev 2014-07-09 15:08:54 -04:00
parent 0d5c5a3d33
commit fa33ed4b4b
6 changed files with 57 additions and 75 deletions

View File

@ -471,21 +471,34 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
private ManagedList<?> getArgumentResolvers(Element element, ParserContext parserContext) {
Element resolversElement = DomUtils.getChildElementByTagName(element, "argument-resolvers");
if (resolversElement != null) {
ManagedList<BeanDefinitionHolder> argumentResolvers = extractBeanSubElements(resolversElement, parserContext);
ManagedList<BeanMetadataElement> customAndReferencedResolvers = new ManagedList<BeanMetadataElement>();
customAndReferencedResolvers.addAll(wrapWebArgumentResolverBeanDefs(argumentResolvers, parserContext));
customAndReferencedResolvers.addAll(extractBeanRefSubElements(resolversElement, parserContext));
return customAndReferencedResolvers;
ManagedList<Object> resolvers = extractBeanSubElements(resolversElement, parserContext);
return wrapLegacyResolvers(resolvers, parserContext);
}
return null;
}
private ManagedList<?> getReturnValueHandlers(Element element, ParserContext parserContext) {
Element handlersElement = DomUtils.getChildElementByTagName(element, "return-value-handlers");
if (handlersElement != null) {
return extractBeanSubElements(handlersElement, parserContext);
private ManagedList<Object> wrapLegacyResolvers(List<Object> list, ParserContext context) {
ManagedList<Object> result = new ManagedList<Object>();
for (Object object : list) {
if (object instanceof BeanDefinitionHolder) {
BeanDefinitionHolder beanDef = (BeanDefinitionHolder) object;
String className = beanDef.getBeanDefinition().getBeanClassName();
Class<?> clazz = ClassUtils.resolveClassName(className, context.getReaderContext().getBeanClassLoader());
if (WebArgumentResolver.class.isAssignableFrom(clazz)) {
RootBeanDefinition adapter = new RootBeanDefinition(ServletWebArgumentResolverAdapter.class);
adapter.getConstructorArgumentValues().addIndexedArgumentValue(0, beanDef);
result.add(new BeanDefinitionHolder(adapter, beanDef.getBeanName() + "Adapter"));
continue;
}
}
result.add(object);
}
return null;
return result;
}
private ManagedList<?> getReturnValueHandlers(Element element, ParserContext parserContext) {
Element handlers = DomUtils.getChildElementByTagName(element, "return-value-handlers");
return (handlers != null ? extractBeanSubElements(handlers, parserContext) : null);
}
private ManagedList<?> getMessageConverters(Element element, Object source, ParserContext parserContext) {
@ -536,13 +549,12 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
private ManagedList<BeanDefinitionHolder> extractBeanSubElements(Element parentElement, ParserContext parserContext) {
ManagedList<BeanDefinitionHolder> list = new ManagedList<BeanDefinitionHolder>();
private ManagedList<Object> extractBeanSubElements(Element parentElement, ParserContext parserContext) {
ManagedList<Object> list = new ManagedList<Object>();
list.setSource(parserContext.extractSource(parentElement));
for (Element beanElement : DomUtils.getChildElementsByTagName(parentElement, "bean")) {
BeanDefinitionHolder beanDef = parserContext.getDelegate().parseBeanDefinitionElement(beanElement);
beanDef = parserContext.getDelegate().decorateBeanDefinitionIfRequired(beanElement, beanDef);
list.add(beanDef);
for (Element beanElement : DomUtils.getChildElementsByTagName(parentElement, "bean", "ref")) {
Object object = parserContext.getDelegate().parsePropertySubElement(beanElement, null);
list.add(object);
}
return list;
}
@ -566,25 +578,6 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
return list;
}
private ManagedList<BeanDefinitionHolder> wrapWebArgumentResolverBeanDefs(
List<BeanDefinitionHolder> beanDefs, ParserContext parserContext) {
ManagedList<BeanDefinitionHolder> result = new ManagedList<BeanDefinitionHolder>();
for (BeanDefinitionHolder beanDef : beanDefs) {
String className = beanDef.getBeanDefinition().getBeanClassName();
Class<?> clazz = ClassUtils.resolveClassName(className, parserContext.getReaderContext().getBeanClassLoader());
if (WebArgumentResolver.class.isAssignableFrom(clazz)) {
RootBeanDefinition adapter = new RootBeanDefinition(ServletWebArgumentResolverAdapter.class);
adapter.getConstructorArgumentValues().addIndexedArgumentValue(0, beanDef);
result.add(new BeanDefinitionHolder(adapter, beanDef.getBeanName() + "Adapter"));
}
else {
result.add(beanDef);
}
}
return result;
}
/**
* A FactoryBean for a CompositeUriComponentsContributor that obtains the

View File

@ -138,8 +138,7 @@
<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
A reference to a HandlerMethodArgumentResolver bean definition.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
@ -160,15 +159,27 @@
]]></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 HandlerMethodReturnValueHandler 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 HandlerMethodReturnValueHandler bean definition.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="java:org.springframework.web.method.support.HandlerMethodReturnValueHandler" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
<xsd:element name="async-support" minOccurs="0">

View File

@ -117,26 +117,13 @@ public class AnnotationDrivenBeanDefinitionParserTests {
assertNotNull(value);
assertTrue(value instanceof List);
List<HandlerMethodArgumentResolver> resolvers = (List<HandlerMethodArgumentResolver>) value;
assertEquals(2, resolvers.size());
assertEquals(3, resolvers.size());
assertTrue(resolvers.get(0) instanceof ServletWebArgumentResolverAdapter);
assertTrue(resolvers.get(1) instanceof TestHandlerMethodArgumentResolver);
assertTrue(resolvers.get(2) instanceof TestHandlerMethodArgumentResolver);
assertNotSame(resolvers.get(1), resolvers.get(2));
}
@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() {
@ -147,8 +134,10 @@ public class AnnotationDrivenBeanDefinitionParserTests {
assertNotNull(value);
assertTrue(value instanceof List);
List<HandlerMethodReturnValueHandler> handlers = (List<HandlerMethodReturnValueHandler>) value;
assertEquals(1, handlers.size());
assertEquals(2, handlers.size());
assertEquals(TestHandlerMethodReturnValueHandler.class, handlers.get(0).getClass());
assertEquals(TestHandlerMethodReturnValueHandler.class, handlers.get(1).getClass());
assertNotSame(handlers.get(0), handlers.get(1));
}
@Test

View File

@ -1,17 +0,0 @@
<?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>

View File

@ -9,7 +9,10 @@
<mvc:argument-resolvers>
<bean class="org.springframework.web.servlet.config.TestWebArgumentResolver"/>
<bean class="org.springframework.web.servlet.config.TestHandlerMethodArgumentResolver"/>
<ref bean="customArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
<bean id="customArgumentResolver" class="org.springframework.web.servlet.config.TestHandlerMethodArgumentResolver"/>
</beans>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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">
@ -8,7 +8,10 @@
<mvc:annotation-driven>
<mvc:return-value-handlers>
<bean class="org.springframework.web.servlet.config.TestHandlerMethodReturnValueHandler"/>
<ref bean="customHandler" />
</mvc:return-value-handlers>
</mvc:annotation-driven>
<bean id="customHandler" class="org.springframework.web.servlet.config.TestHandlerMethodReturnValueHandler"/>
</beans>