From ee553f7804c9cc2ac89b963bcff58974503c20fe Mon Sep 17 00:00:00 2001 From: Chris Beams Date: Wed, 11 Nov 2009 00:48:30 +0000 Subject: [PATCH] SPR-6328: Rename @ImportXml -> @ImportResource and allow for usage of non-XML BeanDefinitionReader types --- .../annotation/ConfigurationClass.java | 11 ++--- ...onfigurationClassBeanDefinitionReader.java | 33 +++++++++++--- .../annotation/ConfigurationClassParser.java | 9 ++-- .../{ImportXml.java => ImportResource.java} | 8 +++- ...ortNonXmlResourceConfig-context.properties | 1 + ...XmlTests.java => ImportResourceTests.java} | 45 +++++++++++++++---- .../ImportXmlWithAopNamespace-context.xml | 2 +- 7 files changed, 83 insertions(+), 26 deletions(-) rename org.springframework.context/src/main/java/org/springframework/context/annotation/{ImportXml.java => ImportResource.java} (79%) create mode 100644 org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportNonXmlResourceConfig-context.properties rename org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/{ImportXmlTests.java => ImportResourceTests.java} (70%) diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java index f56edc81525..150c1958148 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClass.java @@ -24,6 +24,7 @@ import java.util.Set; import org.springframework.beans.factory.parsing.Location; import org.springframework.beans.factory.parsing.Problem; import org.springframework.beans.factory.parsing.ProblemReporter; +import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.core.io.DescriptiveResource; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; @@ -50,7 +51,7 @@ final class ConfigurationClass { private String beanName; - private final Set xmlFilesToImport = new LinkedHashSet(); + private final Map importedResources = new LinkedHashMap(); private final Set methods = new LinkedHashSet(); @@ -107,12 +108,12 @@ final class ConfigurationClass { return this.methods; } - public void addXmlImport(String xmlImport) { - this.xmlFilesToImport.add(xmlImport); + public void addImportedResource(String importedResource, String readerClassName) { + this.importedResources.put(importedResource, readerClassName); } - public Set getXmlImports() { - return this.xmlFilesToImport; + public Map getImportedResources() { + return this.importedResources; } diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 5c34384de01..afc836fa196 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -19,6 +19,7 @@ package org.springframework.context.annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -36,11 +37,12 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.MethodMetadata; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StringUtils; /** @@ -95,7 +97,7 @@ class ConfigurationClassBeanDefinitionReader { loadBeanDefinitionsForModelMethod(method); } - loadBeanDefinitionsFromXml(configClass.getXmlImports()); + loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); } /** @@ -212,10 +214,29 @@ class ConfigurationClassBeanDefinitionReader { registry.registerBeanDefinition(beanName, beanDefToRegister); } - private void loadBeanDefinitionsFromXml(Set xmlImports) { - XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.registry); - // TODO SPR-6310: qualify relatively pathed locations as done in AbstractContextLoader.modifyLocations - reader.loadBeanDefinitions(xmlImports.toArray(new String[]{})); + private void loadBeanDefinitionsFromImportedResources(Map importedResources) { + + HashMap readerInstanceCache = new HashMap(); + + for (String resource : importedResources.keySet()) { + String readerClassName = importedResources.get(resource); + + if (!readerInstanceCache.containsKey(readerClassName)) { + try { + @SuppressWarnings("unchecked") + Class readerClass = + (Class) ClassUtils.forName(readerClassName, ClassUtils.getDefaultClassLoader()); + BeanDefinitionReader readerInstance = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry); + readerInstanceCache.put(readerClassName, readerInstance); + } catch (Exception ex) { + ReflectionUtils.handleReflectionException(ex); + } + } + + BeanDefinitionReader reader = readerInstanceCache.get(readerClassName); + // TODO SPR-6310: qualify relatively pathed locations as done in AbstractContextLoader.modifyLocations + reader.loadBeanDefinitions(importedResources.keySet().toArray(new String[]{})); + } } /** diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index ddbe1b5e4f9..179695c0523 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -28,12 +28,14 @@ import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.parsing.Location; import org.springframework.beans.factory.parsing.Problem; import org.springframework.beans.factory.parsing.ProblemReporter; +import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.MethodMetadata; import org.springframework.core.type.StandardAnnotationMetadata; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.util.ClassUtils; /** * Parses a {@link Configuration} class definition, populating a model (collection) of @@ -128,9 +130,10 @@ class ConfigurationClassParser { if (metadata.isAnnotated(Import.class.getName())) { processImport(configClass, (String[]) metadata.getAnnotationAttributes(Import.class.getName()).get("value")); } - if (metadata.isAnnotated(ImportXml.class.getName())) { - for (String xmlImport : (String[]) metadata.getAnnotationAttributes(ImportXml.class.getName()).get("value")) { - configClass.addXmlImport(xmlImport); + if (metadata.isAnnotated(ImportResource.class.getName())) { + String readerClassName = (String) metadata.getAnnotationAttributes(ImportResource.class.getName()).get("reader"); + for (String importedResource : (String[]) metadata.getAnnotationAttributes(ImportResource.class.getName()).get("value")) { + configClass.addImportedResource(importedResource, readerClassName); } } Set methods = metadata.getAnnotatedMethods(Bean.class.getName()); diff --git a/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportXml.java b/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportResource.java similarity index 79% rename from org.springframework.context/src/main/java/org/springframework/context/annotation/ImportXml.java rename to org.springframework.context/src/main/java/org/springframework/context/annotation/ImportResource.java index 878336d1887..18075cad097 100644 --- a/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportXml.java +++ b/org.springframework.context/src/main/java/org/springframework/context/annotation/ImportResource.java @@ -23,12 +23,16 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.beans.factory.support.BeanDefinitionReader; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; + @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented -@Inherited -public @interface ImportXml { +public @interface ImportResource { String[] value(); + + Class reader() default XmlBeanDefinitionReader.class; } diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportNonXmlResourceConfig-context.properties b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportNonXmlResourceConfig-context.properties new file mode 100644 index 00000000000..3ecf4accbb4 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportNonXmlResourceConfig-context.properties @@ -0,0 +1 @@ +propertiesDeclaredBean.(class)=test.beans.TestBean \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportXmlTests.java b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java similarity index 70% rename from org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportXmlTests.java rename to org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java index 1fc33eb0bfd..0204a757b08 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportXmlTests.java +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportResourceTests.java @@ -26,20 +26,22 @@ import org.junit.Ignore; import org.junit.Test; import org.springframework.aop.support.AopUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.support.PropertiesBeanDefinitionReader; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.ImportXml; +import org.springframework.context.annotation.ImportResource; import test.beans.TestBean; /** - * Integration tests for {@link ImportXml} support. + * Integration tests for {@link ImportResource} support. * * @author Chris Beams */ -public class ImportXmlTests { +public class ImportResourceTests { @Test public void testImportXml() { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ImportXmlConfig.class); @@ -48,7 +50,7 @@ public class ImportXmlTests { } @Configuration - @ImportXml("classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml") + @ImportResource("classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml") static class ImportXmlConfig { public @Bean TestBean javaDeclaredBean() { return new TestBean("java.declared"); @@ -64,7 +66,7 @@ public class ImportXmlTests { } @Configuration - @ImportXml("ImportXmlConfig-context.xml") + @ImportResource("ImportXmlConfig-context.xml") static class ImportXmlWithRelativePathConfig { public @Bean TestBean javaDeclaredBean() { return new TestBean("java.declared"); @@ -97,7 +99,7 @@ public class ImportXmlTests { } @Configuration - @ImportXml("classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml") + @ImportResource("classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml") static class BaseConfig { } @@ -106,7 +108,7 @@ public class ImportXmlTests { } @Configuration - @ImportXml("classpath:org/springframework/context/annotation/configuration/SecondLevelSubConfig-context.xml") + @ImportResource("classpath:org/springframework/context/annotation/configuration/SecondLevelSubConfig-context.xml") static class SecondLevelSubConfig extends BaseConfig { } @@ -118,7 +120,7 @@ public class ImportXmlTests { } @Configuration - @ImportXml("classpath:org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml") + @ImportResource("classpath:org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml") static class ImportXmlWithAopNamespaceConfig { } @@ -136,7 +138,7 @@ public class ImportXmlTests { } @Configuration - @ImportXml(value="classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml") + @ImportResource(value="classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml") static class ImportXmlAutowiredConfig { @Autowired TestBean xmlDeclaredBean; @@ -144,5 +146,30 @@ public class ImportXmlTests { return xmlDeclaredBean.getName(); } } + + @Test + public void testImportNonXmlResource() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(ImportNonXmlResourceConfig.class); + assertTrue(ctx.containsBean("propertiesDeclaredBean")); + } + @Configuration + @ImportResource(value="classpath:org/springframework/context/annotation/configuration/ImportNonXmlResourceConfig-context.properties", + reader=PropertiesBeanDefinitionReader.class) + static class ImportNonXmlResourceConfig { + } + + @Ignore // TODO: SPR-6327 + @Test + public void testImportDifferentResourceTypes() { + AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SubResourceConfig.class); + assertTrue(ctx.containsBean("propertiesDeclaredBean")); + assertTrue(ctx.containsBean("xmlDeclaredBean")); + } + + @Configuration + @ImportResource(value="classpath:org/springframework/context/annotation/configuration/ImportXmlConfig-context.xml", + reader=XmlBeanDefinitionReader.class) + static class SubResourceConfig extends ImportNonXmlResourceConfig { + } } \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml index 24a6e3bb513..44fc77e3b5e 100644 --- a/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml +++ b/org.springframework.context/src/test/java/org/springframework/context/annotation/configuration/ImportXmlWithAopNamespace-context.xml @@ -7,7 +7,7 @@ - +