diff --git a/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java b/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java index 534f80cd949..0146c39b798 100644 --- a/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java +++ b/spring-beans-groovy/src/main/java/org/springframework/beans/factory/groovy/GroovyBeanDefinitionReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -53,7 +53,7 @@ import org.springframework.beans.factory.xml.XmlReaderContext; import org.springframework.core.io.DescriptiveResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.EncodedResource; -import org.springframework.core.io.support.ResourcePatternUtils; +import org.springframework.util.StringUtils; /** * A Groovy-based reader for Spring bean definitions: like a Groovy builder, @@ -108,6 +108,9 @@ import org.springframework.core.io.support.ResourcePatternUtils; * } * } * + *

This bean definition reader also understands XML bean definition files, + * allowing for seamless mixing and matching with Groovy bean definition files. + * *

Typically applied to a * {@link org.springframework.beans.factory.support.DefaultListableBeanFactory} * or a {@link org.springframework.context.support.GenericApplicationContext}, @@ -187,7 +190,9 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp // TRADITIONAL BEAN DEFINITION READER METHODS /** - * Load bean definitions from the specified Groovy script. + * Load bean definitions from the specified Groovy script or XML file. + *

Note that ".xml" files will be parsed as XML content; all other kinds + * of resources will be parsed as Groovy scripts. * @param resource the resource descriptor for the Groovy script * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors @@ -197,14 +202,22 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp } /** - * Load bean definitions from the specified Groovy script. + * Load bean definitions from the specified Groovy script or XML file. + *

Note that ".xml" files will be parsed as XML content; all other kinds + * of resources will be parsed as Groovy scripts. * @param encodedResource the resource descriptor for the Groovy script, * allowing to specify an encoding to use for parsing the file * @return the number of bean definitions found * @throws BeanDefinitionStoreException in case of loading or parsing errors */ public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { - Closure beans = new Closure(this){ + // Check for XML files and redirect them to the XmlBeanDefinitionReader + String filename = encodedResource.getResource().getFilename(); + if (StringUtils.endsWithIgnoreCase(filename, ".xml")) { + return this.xmlBeanDefinitionReader.loadBeanDefinitions(encodedResource); + } + + Closure beans = new Closure(this) { public Object call(Object[] args) { invokeBeanDefiningClosure((Closure) args[0]); return null; @@ -213,7 +226,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp Binding binding = new Binding() { @Override public void setVariable(String name, Object value) { - if (currentBeanDefinition !=null) { + if (currentBeanDefinition != null) { applyPropertyToBeanDefinition(name, value); } else { @@ -321,17 +334,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp * @param resourcePattern the resource pattern */ public void importBeans(String resourcePattern) throws IOException { - Resource[] resources = - ResourcePatternUtils.getResourcePatternResolver(getResourceLoader()).getResources(resourcePattern); - for (Resource resource : resources) { - String filename = resource.getFilename(); - if (filename.endsWith(".groovy")) { - loadBeanDefinitions(resource); - } - else if (filename.endsWith(".xml")) { - this.xmlBeanDefinitionReader.loadBeanDefinitions(resource); - } - } + loadBeanDefinitions(resourcePattern); } @@ -410,7 +413,7 @@ public class GroovyBeanDefinitionReader extends AbstractBeanDefinitionReader imp } dp.apply(); } - deferredProperties.clear(); + this.deferredProperties.clear(); } /** diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java index 7c6566fc8d1..903431ad809 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassBeanDefinitionReader.java @@ -33,6 +33,7 @@ import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; import org.springframework.beans.factory.parsing.Location; import org.springframework.beans.factory.parsing.Problem; import org.springframework.beans.factory.parsing.ProblemReporter; @@ -42,6 +43,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.annotation.ConfigurationCondition.ConfigurationPhase; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.Environment; @@ -287,28 +289,42 @@ class ConfigurationClassBeanDefinitionReader { Map> importedResources) { Map, BeanDefinitionReader> readerInstanceCache = new HashMap, BeanDefinitionReader>(); + for (Map.Entry> entry : importedResources.entrySet()) { String resource = entry.getKey(); Class readerClass = entry.getValue(); - if (!readerInstanceCache.containsKey(readerClass)) { + + // Default reader selection necessary? + if (readerClass.equals(BeanDefinitionReader.class)) { + if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) { + // When clearly asking for Groovy, that's what they'll get... + readerClass = GroovyBeanDefinitionReader.class; + } + else { + // Primarily ".xml" files but for any other extension as well + readerClass = XmlBeanDefinitionReader.class; + } + } + + BeanDefinitionReader reader = readerInstanceCache.get(readerClass); + if (reader == null) { try { // Instantiate the specified BeanDefinitionReader - BeanDefinitionReader readerInstance = - readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry); + reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry); // Delegate the current ResourceLoader to it if possible - if (readerInstance instanceof AbstractBeanDefinitionReader) { - AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) readerInstance); + if (reader instanceof AbstractBeanDefinitionReader) { + AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader); abdr.setResourceLoader(this.resourceLoader); abdr.setEnvironment(this.environment); } - readerInstanceCache.put(readerClass, readerInstance); + readerInstanceCache.put(readerClass, reader); } catch (Exception ex) { throw new IllegalStateException( "Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]"); } } - BeanDefinitionReader reader = readerInstanceCache.get(readerClass); + // TODO SPR-6310: qualify relative path locations as done in AbstractContextLoader.modifyLocations reader.loadBeanDefinitions(resource); } diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ImportResource.java b/spring-context/src/main/java/org/springframework/context/annotation/ImportResource.java index 16506965d9b..15345132f25 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ImportResource.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ImportResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * Copyright 2002-2014 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. @@ -23,25 +23,25 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.beans.factory.support.BeanDefinitionReader; -import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; /** * Indicates one or more resources containing bean definitions to import. * - *

Like {@link Import @Import}, this annotation provides functionality similar to the - * {@code } element in Spring XML. It is typically used when - * designing {@link Configuration @Configuration} classes to be bootstrapped by - * {@link AnnotationConfigApplicationContext}, but where some XML functionality such as - * namespaces is still necessary. + *

Like {@link Import @Import}, this annotation provides functionality similar to + * the {@code } element in Spring XML. It is typically used when designing + * {@link Configuration @Configuration} classes to be bootstrapped by + * {@link AnnotationConfigApplicationContext}, but where some XML functionality such + * as namespaces is still necessary. * *

By default, arguments to the {@link #value()} attribute will be processed using - * an {@link XmlBeanDefinitionReader}, i.e. it is assumed that resources are Spring - * {@code } XML files. Optionally, the {@link #reader()} attribute may be - * supplied, allowing the user to specify a different {@link BeanDefinitionReader} - * implementation, such as - * {@link org.springframework.beans.factory.support.PropertiesBeanDefinitionReader}. + * {@link org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader} if ending in + * ".groovy"; otherwise, {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader} + * will be used to parse Spring {@code } XML files. Optionally, the {@link #reader()} + * attribute may be supplied, allowing the user to choose a custom {@link BeanDefinitionReader} + * implementation. * * @author Chris Beams + * @author Juergen Hoeller * @since 3.0 * @see Configuration * @see Import @@ -52,15 +52,22 @@ import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; public @interface ImportResource { /** - * Resource paths to import. Resource-loading prefixes such as {@code classpath:} and - * {@code file:}, etc may be used. + * Resource paths to import. Resource-loading prefixes such as {@code classpath:} + * and {@code file:}, etc may be used. + *

Out of the box, ".groovy" files are going to be specifically parsed with + * {@link org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader}; + * others with {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}. */ String[] value(); /** - * {@link BeanDefinitionReader} implementation to use when processing resources specified - * by the {@link #value()} attribute. + * {@link BeanDefinitionReader} implementation to use when processing resources + * specified by the {@link #value()} attribute. + *

By default, the reader will be adapted to the resource path specified: + * ".groovy" files are going to be specifically parsed with + * {@link org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader}; + * others with {@link org.springframework.beans.factory.xml.XmlBeanDefinitionReader}. */ - Class reader() default XmlBeanDefinitionReader.class; + Class reader() default BeanDefinitionReader.class; } diff --git a/spring-context/src/main/java/org/springframework/context/support/GenericGroovyApplicationContext.java b/spring-context/src/main/java/org/springframework/context/support/GenericGroovyApplicationContext.java index f2b511031f4..b68a694120f 100644 --- a/spring-context/src/main/java/org/springframework/context/support/GenericGroovyApplicationContext.java +++ b/spring-context/src/main/java/org/springframework/context/support/GenericGroovyApplicationContext.java @@ -35,8 +35,9 @@ import org.springframework.core.io.Resource; * can be retrieved with the dot de-reference syntax instead of using {@link #getBean}. * *

Consider this as the equivalent of {@link GenericXmlApplicationContext} for - * Groovy bean definitions. The main difference is that, within a Groovy script, - * the context can be used with an inline bean definition closure as follows: + * Groovy bean definitions, or even an upgrade thereof since it seamlessly understands + * XML bean definition files as well. The main difference is that, within a Groovy + * script, the context can be used with an inline bean definition closure as follows: * *

  * import org.hibernate.SessionFactory
@@ -104,6 +105,11 @@ import org.springframework.core.io.Resource;
  * ApplicationContext context = new GenericGroovyApplicationContext("org/myapp/applicationContext.groovy");
  * 
* + *

This application context also understands XML bean definition files, + * allowing for seamless mixing and matching with Groovy bean definition files. + * ".xml" files will be parsed as XML content; all other kinds of resources will + * be parsed as Groovy scripts. + * * @author Juergen Hoeller * @author Jeff Brown * @since 4.0 @@ -180,7 +186,9 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i } /** - * Load bean definitions from the given Groovy scripts. + * Load bean definitions from the given Groovy scripts or XML files. + *

Note that ".xml" files will be parsed as XML content; all other kinds + * of resources will be parsed as Groovy scripts. * @param resources one or more resources to load from */ public void load(Resource... resources) { @@ -188,7 +196,9 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i } /** - * Load bean definitions from the given Groovy scripts. + * Load bean definitions from the given Groovy scripts or XML files. + *

Note that ".xml" files will be parsed as XML content; all other kinds + * of resources will be parsed as Groovy scripts. * @param resourceLocations one or more resource locations to load from */ public void load(String... resourceLocations) { @@ -196,7 +206,9 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i } /** - * Load bean definitions from the given Groovy scripts. + * Load bean definitions from the given Groovy scripts or XML files. + *

Note that ".xml" files will be parsed as XML content; all other kinds + * of resources will be parsed as Groovy scripts. * @param relativeClass class whose package will be used as a prefix when * loading each specified resource name * @param resourceNames relatively-qualified names of resources to load @@ -206,7 +218,7 @@ public class GenericGroovyApplicationContext extends GenericApplicationContext i for (int i = 0; i < resourceNames.length; i++) { resources[i] = new ClassPathResource(resourceNames[i], relativeClass); } - this.load(resources); + load(resources); } diff --git a/spring-web/src/main/java/org/springframework/web/context/support/GroovyWebApplicationContext.java b/spring-web/src/main/java/org/springframework/web/context/support/GroovyWebApplicationContext.java index b578ce7647e..684bf1cdc3a 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/GroovyWebApplicationContext.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/GroovyWebApplicationContext.java @@ -30,8 +30,8 @@ import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader; import org.springframework.beans.factory.support.DefaultListableBeanFactory; /** - * {@link org.springframework.web.context.WebApplicationContext} implementation - * which takes its configuration from Groovy bean definition scripts, understood by + * {@link org.springframework.web.context.WebApplicationContext} implementation which takes + * its configuration from Groovy bean definition scripts and/or XML files, as understood by * an {@link org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader}. * This is essentially the equivalent of * {@link org.springframework.context.support.GenericGroovyApplicationContext} @@ -46,7 +46,8 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory; * init-param of {@link org.springframework.web.servlet.FrameworkServlet}. Config locations * can either denote concrete files like "/WEB-INF/context.groovy" or Ant-style patterns * like "/WEB-INF/*-context.groovy" (see {@link org.springframework.util.PathMatcher} - * javadoc for pattern details). + * javadoc for pattern details). Note that ".xml" files will be parsed as XML content; + * all other kinds of resources will be parsed as Groovy scripts. * *

Note: In case of multiple config locations, later bean definitions will * override ones defined in earlier loaded files. This can be leveraged to @@ -119,7 +120,7 @@ public class GroovyWebApplicationContext extends AbstractRefreshableWebApplicati * therefore this method is just supposed to load and/or register bean definitions. *

Delegates to a ResourcePatternResolver for resolving location patterns * into Resource instances. - * @throws IOException if the required Groovy script isn't found + * @throws IOException if the required Groovy script or XML file isn't found * @see #refreshBeanFactory * @see #getConfigLocations * @see #getResources