diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java index 12aae160a8b..07622098b75 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java @@ -13,13 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.web.servlet.config; +import org.w3c.dom.Element; + import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.convert.ConversionService; @@ -30,7 +33,6 @@ import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping; -import org.w3c.dom.Element; /** * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses the {@code annotation-driven} element to configure @@ -46,84 +48,70 @@ import org.w3c.dom.Element; *
  • Configures the validator if specified, otherwise defaults to a fresh {@link Validator} instance created by the default {@link LocalValidatorFactoryBean} if the JSR-303 API is present in the classpath. * * + * * @author Keith Donald + * @author Juergen Hoeller * @since 3.0 */ -public class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { +class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { + + private static final boolean jsr303Present = ClassUtils.isPresent( + "javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader()); + public BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); - BeanDefinitionHolder handlerMappingHolder = registerDefaultAnnotationHandlerMapping(element, source, parserContext); - BeanDefinitionHolder handlerAdapterHolder = registerAnnotationMethodHandlerAdapter(element, source, parserContext); - + + RootBeanDefinition mappingDef = new RootBeanDefinition(DefaultAnnotationHandlerMapping.class); + mappingDef.setSource(source); + mappingDef.getPropertyValues().add("order", 0); + String mappingName = parserContext.getReaderContext().registerWithGeneratedName(mappingDef); + + RootBeanDefinition bindingDef = new RootBeanDefinition(ConfigurableWebBindingInitializer.class); + bindingDef.setSource(source); + bindingDef.getPropertyValues().add("conversionService", getConversionService(element, source, parserContext)); + bindingDef.getPropertyValues().add("validator", getValidator(element, source, parserContext)); + + RootBeanDefinition adapterDef = new RootBeanDefinition(AnnotationMethodHandlerAdapter.class); + adapterDef.setSource(source); + adapterDef.getPropertyValues().add("webBindingInitializer", bindingDef); + String adapterName = parserContext.getReaderContext().registerWithGeneratedName(adapterDef); + CompositeComponentDefinition compDefinition = new CompositeComponentDefinition(element.getTagName(), source); parserContext.pushContainingComponent(compDefinition); - parserContext.registerComponent(new BeanComponentDefinition(handlerMappingHolder)); - parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterHolder)); + parserContext.registerComponent(new BeanComponentDefinition(mappingDef, mappingName)); + parserContext.registerComponent(new BeanComponentDefinition(adapterDef, adapterName)); parserContext.popAndRegisterContainingComponent(); return null; } - // internal helpers - - private BeanDefinitionHolder registerDefaultAnnotationHandlerMapping(Element element, Object source, ParserContext context) { - BeanDefinitionBuilder builder = createBeanBuilder(DefaultAnnotationHandlerMapping.class, source); - builder.addPropertyValue("order", 0); - return registerBeanDefinition(builder.getBeanDefinition(), context); - } - private BeanDefinitionHolder registerAnnotationMethodHandlerAdapter(Element element, Object source, ParserContext context) { - BeanDefinitionBuilder builder = createBeanBuilder(AnnotationMethodHandlerAdapter.class, source); - builder.addPropertyValue("webBindingInitializer", createWebBindingInitializer(element, source, context)); - return registerBeanDefinition(builder.getBeanDefinition(), context); - } - - private BeanDefinition createWebBindingInitializer(Element element, Object source, ParserContext context) { - BeanDefinitionBuilder builder = createBeanBuilder(ConfigurableWebBindingInitializer.class, source); - addConversionService(builder, element, source, context); - addValidator(builder, element, source, context); - return builder.getBeanDefinition(); - } - - private void addConversionService(BeanDefinitionBuilder builder, Element element, Object source, ParserContext context) { + private Object getConversionService(Element element, Object source, ParserContext parserContext) { if (element.hasAttribute("conversion-service")) { - builder.addPropertyReference("conversionService", element.getAttribute("conversion-service")); - } else { - builder.addPropertyValue("conversionService", createDefaultConversionService(element, source, context)); + return new RuntimeBeanReference(element.getAttribute("conversion-service")); + } + else { + RootBeanDefinition conversionDef = new RootBeanDefinition(FormattingConversionServiceFactoryBean.class); + conversionDef.setSource(source); + String conversionName = parserContext.getReaderContext().registerWithGeneratedName(conversionDef); + return new RuntimeBeanReference(conversionName); } } - private void addValidator(BeanDefinitionBuilder builder, Element element, Object source, ParserContext context) { + private Object getValidator(Element element, Object source, ParserContext parserContext) { if (element.hasAttribute("validator")) { - builder.addPropertyReference("validator", element.getAttribute("validator")); - } else { - if (ClassUtils.isPresent("javax.validation.Validator", AnnotationDrivenBeanDefinitionParser.class.getClassLoader())) { - builder.addPropertyValue("validator", createDefaultValidator(element, source, context)); - } + return new RuntimeBeanReference(element.getAttribute("validator")); + } + else if (jsr303Present) { + RootBeanDefinition validatorDef = new RootBeanDefinition(LocalValidatorFactoryBean.class); + validatorDef.setSource(source); + String validatorName = parserContext.getReaderContext().registerWithGeneratedName(validatorDef); + return new RuntimeBeanReference(validatorName); + } + else { + return null; } - } - - private BeanDefinition createDefaultConversionService(Element element, Object source, ParserContext context) { - BeanDefinitionBuilder builder = createBeanBuilder(FormattingConversionServiceFactoryBean.class, source); - return builder.getBeanDefinition(); - } - - private BeanDefinition createDefaultValidator(Element element, Object source, ParserContext context) { - BeanDefinitionBuilder builder = createBeanBuilder(LocalValidatorFactoryBean.class, source); - return builder.getBeanDefinition(); - } - - private BeanDefinitionHolder registerBeanDefinition(BeanDefinition definition, ParserContext context) { - String beanName = context.getReaderContext().generateBeanName(definition); - context.getRegistry().registerBeanDefinition(beanName, definition); - return new BeanDefinitionHolder(definition, beanName); - } - - private BeanDefinitionBuilder createBeanBuilder(Class clazz, Object source) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); - builder.getRawBeanDefinition().setSource(source); - return builder; } } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcNamespaceHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcNamespaceHandler.java index 43f8168d72c..c295b11b476 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcNamespaceHandler.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcNamespaceHandler.java @@ -21,11 +21,14 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport; /** * {@link NamespaceHandler} for Spring MVC configuration namespace. + * * @author Keith Donald + * @since 3.0 */ public class MvcNamespaceHandler extends NamespaceHandlerSupport { public void init() { registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser()); } + } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java index 7403c74a30b..162011420ad 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java @@ -1,24 +1,38 @@ -package org.springframework.web.servlet.config; +/* + * Copyright 2002-2009 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. + */ -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +package org.springframework.web.servlet.config; import java.util.Date; import java.util.Locale; - import javax.validation.Valid; import javax.validation.constraints.NotNull; +import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; + import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.convert.ConversionFailedException; +import org.springframework.core.convert.ConversionService; import org.springframework.core.io.ClassPathResource; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat.ISO; +import org.springframework.format.support.FormattingConversionServiceFactoryBean; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletContext; @@ -26,33 +40,41 @@ import org.springframework.stereotype.Controller; import org.springframework.validation.BindingResult; import org.springframework.validation.Errors; import org.springframework.validation.Validator; +import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.context.support.GenericWebApplicationContext; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; import org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping; +/** + * @author Keith Donald + */ public class MvcNamespaceTests { private GenericWebApplicationContext container; - + @Before public void setUp() { container = new GenericWebApplicationContext(); container.setServletContext(new MockServletContext()); LocaleContextHolder.setLocale(Locale.US); } - + @Test public void testDefaultConfig() throws Exception { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container); reader.loadBeanDefinitions(new ClassPathResource("mvc-config.xml", getClass())); - assertEquals(2, container.getBeanDefinitionCount()); + assertEquals(4, container.getBeanDefinitionCount()); DefaultAnnotationHandlerMapping mapping = container.getBean(DefaultAnnotationHandlerMapping.class); assertNotNull(mapping); assertEquals(0, mapping.getOrder()); AnnotationMethodHandlerAdapter adapter = container.getBean(AnnotationMethodHandlerAdapter.class); assertNotNull(adapter); + assertNotNull(container.getBean(FormattingConversionServiceFactoryBean.class)); + assertNotNull(container.getBean(ConversionService.class)); + assertNotNull(container.getBean(LocalValidatorFactoryBean.class)); + assertNotNull(container.getBean(Validator.class)); TestController handler = new TestController(); @@ -68,12 +90,13 @@ public class MvcNamespaceTests { public void testCustomConversionService() throws Exception { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container); reader.loadBeanDefinitions(new ClassPathResource("mvc-config-custom-conversion-service.xml", getClass())); - assertEquals(3, container.getBeanDefinitionCount()); + assertEquals(4, container.getBeanDefinitionCount()); DefaultAnnotationHandlerMapping mapping = container.getBean(DefaultAnnotationHandlerMapping.class); assertNotNull(mapping); assertEquals(0, mapping.getOrder()); AnnotationMethodHandlerAdapter adapter = container.getBean(AnnotationMethodHandlerAdapter.class); assertNotNull(adapter); + assertNotNull(container.getBean(LocalValidatorFactoryBean.class)); TestController handler = new TestController(); @@ -88,12 +111,13 @@ public class MvcNamespaceTests { public void testCustomValidator() throws Exception { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(container); reader.loadBeanDefinitions(new ClassPathResource("mvc-config-custom-validator.xml", getClass())); - assertEquals(3, container.getBeanDefinitionCount()); + assertEquals(4, container.getBeanDefinitionCount()); DefaultAnnotationHandlerMapping mapping = container.getBean(DefaultAnnotationHandlerMapping.class); assertNotNull(mapping); assertEquals(0, mapping.getOrder()); AnnotationMethodHandlerAdapter adapter = container.getBean(AnnotationMethodHandlerAdapter.class); assertNotNull(adapter); + assertNotNull(container.getBean(FormattingConversionServiceFactoryBean.class)); TestController handler = new TestController(); @@ -150,4 +174,5 @@ public class MvcNamespaceTests { } } + }