diff --git a/build.gradle b/build.gradle index 91ea5725e2..715f1c5c3e 100644 --- a/build.gradle +++ b/build.gradle @@ -929,6 +929,7 @@ project("spring-test") { optional("javax.portlet:portlet-api:2.0") optional("javax.el:javax.el-api:2.2.5") optional("org.aspectj:aspectjweaver:${aspectjVersion}") + optional("org.codehaus.groovy:groovy-all:${groovyVersion}") optional("org.hamcrest:hamcrest-core:1.3") optional("com.jayway.jsonpath:json-path:0.9.0") optional("org.skyscreamer:jsonassert:1.2.3") diff --git a/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java b/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java index a716284a90..f298dc787c 100644 --- a/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java +++ b/spring-test/src/main/java/org/springframework/test/context/ContextConfiguration.java @@ -27,48 +27,52 @@ import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; /** - * {@code @ContextConfiguration} defines class-level metadata that is - * used to determine how to load and configure an - * {@link org.springframework.context.ApplicationContext ApplicationContext} - * for integration tests. + * {@code @ContextConfiguration} defines class-level metadata that is used to determine + * how to load and configure an {@link org.springframework.context.ApplicationContext + * ApplicationContext} for integration tests. * *
Prior to Spring 3.1, only path-based resource locations were supported. - * As of Spring 3.1, {@linkplain #loader context loaders} may choose to support - * either path-based or class-based resources. As of Spring - * 4.0.4, {@linkplain #loader context loaders} may choose to support path-based + *
+ * Prior to Spring 3.1, only path-based resource locations (typically XML configuration + * files) were supported. As of Spring 3.1, {@linkplain #loader context loaders} may + * choose to support either path-based or class-based resources. As of + * Spring 4.0.4, {@linkplain #loader context loaders} may choose to support path-based * and class-based resources simultaneously. Consequently - * {@code @ContextConfiguration} can be used to declare either path-based - * resource locations (via the {@link #locations} or {@link #value} attribute) - * or annotated classes (via the {@link #classes} attribute). Note, - * however, that most implementations of {@link SmartContextLoader} only support - * a single resource type. + * {@code @ContextConfiguration} can be used to declare either path-based resource + * locations (via the {@link #locations} or {@link #value} attribute) or + * annotated classes (via the {@link #classes} attribute). Note, however, that most + * implementations of {@link SmartContextLoader} only support a single resource type. As + * of Spring 4.1, path-based resource locations may be either XML configuration files or + * Groovy scripts (if Groovy is on the classpath). Of course, third-party frameworks may + * choose to support additional types of path-based resources. * *
The term annotated class can refer to any of the following. + *
+ * The term annotated class can refer to any of the following. * *
Consult the Javadoc for - * {@link org.springframework.context.annotation.Configuration @Configuration} and - * {@link org.springframework.context.annotation.Bean @Bean} - * for further information regarding the configuration and semantics of + *
+ * Consult the Javadoc for {@link org.springframework.context.annotation.Configuration + * @Configuration} and {@link org.springframework.context.annotation.Bean @Bean} for + * further information regarding the configuration and semantics of * annotated classes. * - *
As of Spring Framework 4.0, this annotation may be used as a - * meta-annotation to create custom composed annotations. + *
+ * As of Spring Framework 4.0, this annotation may be used as a meta-annotation + * to create custom composed annotations. * * @author Sam Brannen * @since 2.5 @@ -104,20 +108,20 @@ public @interface ContextConfiguration { *
Check out the Javadoc for * {@link org.springframework.test.context.support.AbstractContextLoader#modifyLocations * AbstractContextLoader.modifyLocations()} for details on how a location - * String will be interpreted at runtime, in particular in case of a relative + * will be interpreted at runtime, in particular in case of a relative * path. Also, check out the documentation on * {@link org.springframework.test.context.support.AbstractContextLoader#generateDefaultLocations - * AbstractContextLoader.generateDefaultLocations()} for details on the default - * locations that are going to be used if none are specified. + * AbstractContextLoader.generateDefaultLocations()} for details on the + * default locations that are going to be used if none are specified. * - *
Note that the above-mentioned default rules only apply for a standard + *
Note that the aforementioned default rules only apply for a standard * {@link org.springframework.test.context.support.AbstractContextLoader * AbstractContextLoader} subclass such as - * {@link org.springframework.test.context.support.GenericXmlContextLoader - * GenericXmlContextLoader} which is the effective default implementation - * used at runtime if {@code locations} are configured. See the - * documentation for {@link #loader} for further details regarding default - * loaders. + * {@link org.springframework.test.context.support.GenericXmlContextLoader GenericXmlContextLoader} or + * {@link org.springframework.test.context.support.GenericGroovyXmlContextLoader GenericGroovyXmlContextLoader} + * which are the effective default implementations used at runtime if + * {@code locations} are configured. See the documentation for {@link #loader} + * for further details regarding default loaders. * *
This attribute may not be used in conjunction with * {@link #value}, but it may be used instead of {@link #value}. @@ -186,17 +190,17 @@ public @interface ContextConfiguration { *
In the following example that uses path-based resource locations, the * {@link org.springframework.context.ApplicationContext ApplicationContext} * for {@code ExtendedTest} will be loaded from - * "base-context.xml" and - * "extended-context.xml", in that order. Beans defined in - * "extended-context.xml" may therefore override those defined in - * "base-context.xml". + * {@code "base-context.xml"} and + * {@code "extended-context.xml"}, in that order. Beans defined in + * {@code "extended-context.xml"} may therefore override those defined + * in {@code "base-context.xml"}. *
- * @ContextConfiguration("base-context.xml")
+ * @ContextConfiguration("base-context.xml")
* public class BaseTest {
* // ...
* }
*
- * @ContextConfiguration("extended-context.xml")
+ * @ContextConfiguration("extended-context.xml")
* public class ExtendedTest extends BaseTest {
* // ...
* }
@@ -281,16 +285,13 @@ public @interface ContextConfiguration {
* {@link org.springframework.test.context.web.WebAppConfiguration
* @WebAppConfiguration}. For further details on the default behavior
* of various concrete {@code SmartContextLoaders}, check out the Javadoc for
- * {@link org.springframework.test.context.support.AbstractContextLoader
- * AbstractContextLoader},
- * {@link org.springframework.test.context.support.GenericXmlContextLoader
- * GenericXmlContextLoader},
- * {@link org.springframework.test.context.support.AnnotationConfigContextLoader
- * AnnotationConfigContextLoader},
- * {@link org.springframework.test.context.web.GenericXmlWebContextLoader
- * GenericXmlWebContextLoader}, and
- * {@link org.springframework.test.context.web.AnnotationConfigWebContextLoader
- * AnnotationConfigWebContextLoader}.
+ * {@link org.springframework.test.context.support.AbstractContextLoader AbstractContextLoader},
+ * {@link org.springframework.test.context.support.GenericXmlContextLoader GenericXmlContextLoader},
+ * {@link org.springframework.test.context.support.GenericGroovyXmlContextLoader GenericGroovyXmlContextLoader},
+ * {@link org.springframework.test.context.support.AnnotationConfigContextLoader AnnotationConfigContextLoader},
+ * {@link org.springframework.test.context.web.GenericXmlWebContextLoader GenericXmlWebContextLoader},
+ * {@link org.springframework.test.context.web.GenericGroovyXmlWebContextLoader GenericGroovyXmlWebContextLoader}, and
+ * {@link org.springframework.test.context.web.AnnotationConfigWebContextLoader AnnotationConfigWebContextLoader}.
*
* @since 2.5
*/
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java
index e21f4e5e75..23181b8a88 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java
@@ -55,6 +55,7 @@ import org.springframework.util.ResourceUtils;
* @author Juergen Hoeller
* @since 2.5
* @see #generateDefaultLocations
+ * @see #getResourceSuffixes
* @see #modifyLocations
*/
public abstract class AbstractContextLoader implements SmartContextLoader {
@@ -144,14 +145,14 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
// --- ContextLoader -------------------------------------------------------
/**
- * If the supplied {@code locations} are {@code null} or
- * empty and {@link #isGenerateDefaultLocations()} returns
- * {@code true}, default locations will be
- * {@link #generateDefaultLocations(Class) generated} for the specified
- * {@link Class class} and the configured
- * {@link #getResourceSuffix() resource suffix}; otherwise, the supplied
- * {@code locations} will be {@link #modifyLocations modified} if
- * necessary and returned.
+ * If the supplied {@code locations} are {@code null} or empty
+ * and {@link #isGenerateDefaultLocations()} returns {@code true},
+ * default locations will be {@link #generateDefaultLocations(Class)
+ * generated} (i.e., detected) for the specified {@link Class class}
+ * and the configured {@linkplain #getResourceSuffixes() resource suffixes};
+ * otherwise, the supplied {@code locations} will be
+ * {@linkplain #modifyLocations modified} if necessary and returned.
+ *
* @param clazz the class with which the locations are associated: to be
* used when generating default locations
* @param locations the unmodified locations to use for loading the
@@ -173,45 +174,57 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
/**
* Generate the default classpath resource locations array based on the
* supplied class.
+ *
* For example, if the supplied class is {@code com.example.MyTest},
* the generated locations will contain a single string with a value of
- * "classpath:com/example/MyTest{@code }",
- * where {@code } is the value of the
- * {@link #getResourceSuffix() resource suffix} string.
+ * {@code "classpath:com/example/MyTest"}, where {@code }
+ * is the value of the first configured
+ * {@linkplain #getResourceSuffixes() resource suffix} for which the
+ * generated location actually exists in the classpath.
+ *
* As of Spring 3.1, the implementation of this method adheres to the
* contract defined in the {@link SmartContextLoader} SPI. Specifically,
* this method will preemptively verify that the generated default
* location actually exists. If it does not exist, this method will log a
* warning and return an empty array.
+ *
*
Subclasses can override this method to implement a different
* default location generation strategy.
+ *
* @param clazz the class for which the default locations are to be generated
* @return an array of default application context resource locations
* @since 2.5
- * @see #getResourceSuffix()
+ * @see #getResourceSuffixes()
*/
protected String[] generateDefaultLocations(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
- String suffix = getResourceSuffix();
- Assert.hasText(suffix, "Resource suffix must not be empty");
- String resourcePath = ClassUtils.convertClassNameToResourcePath(clazz.getName()) + suffix;
- String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath;
- ClassPathResource classPathResource = new ClassPathResource(resourcePath);
- if (classPathResource.exists()) {
- if (logger.isInfoEnabled()) {
- logger.info(String.format("Detected default resource location \"%s\" for test class [%s]",
- prefixedResourcePath, clazz.getName()));
+ String[] suffixes = getResourceSuffixes();
+ for (String suffix : suffixes) {
+ Assert.hasText(suffix, "Resource suffix must not be empty");
+ String resourcePath = ClassUtils.convertClassNameToResourcePath(clazz.getName()) + suffix;
+ String prefixedResourcePath = ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath;
+ ClassPathResource classPathResource = new ClassPathResource(resourcePath);
+
+ if (classPathResource.exists()) {
+ if (logger.isInfoEnabled()) {
+ logger.info(String.format("Detected default resource location \"%s\" for test class [%s]",
+ prefixedResourcePath, clazz.getName()));
+ }
+ return new String[] { prefixedResourcePath };
}
- return new String[] { prefixedResourcePath };
- }
- else {
- if (logger.isInfoEnabled()) {
- logger.info(String.format("Could not detect default resource locations for test class [%s]: "
+ else if (logger.isDebugEnabled()) {
+ logger.debug(String.format("Did not detect default resource location for test class [%s]: "
+ "%s does not exist", clazz.getName(), classPathResource));
}
- return EMPTY_STRING_ARRAY;
}
+
+ if (logger.isInfoEnabled()) {
+ logger.info(String.format("Could not detect default resource locations for test class [%s]: "
+ + "no resource found for suffixes %s.", clazz.getName(), ObjectUtils.nullSafeToString(suffixes)));
+ }
+
+ return EMPTY_STRING_ARRAY;
}
/**
@@ -250,13 +263,36 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
}
/**
- * Get the suffix to append to {@link ApplicationContext} resource locations
- * when generating default locations.
- *
Must be implemented by subclasses.
- * @return the resource suffix; should not be {@code null} or empty
+ * Get the suffix to append to {@link ApplicationContext} resource
+ * locations when detecting default locations.
+ *
+ *
Subclasses must provide an implementation of this method that
+ * returns a single suffix. Alternatively subclasses may provide a
+ * no-op implementation of this method and override
+ * {@link #getResourceSuffixes()} in order to provide multiple custom
+ * suffixes.
+ *
+ * @return the resource suffix; never {@code null} or empty
* @since 2.5
* @see #generateDefaultLocations(Class)
+ * @see #getResourceSuffixes()
*/
protected abstract String getResourceSuffix();
+ /**
+ * Get the suffixes to append to {@link ApplicationContext} resource
+ * locations when detecting default locations.
+ *
+ *
The default implementation simply wraps the value returned by
+ * {@link #getResourceSuffix()} in a single-element array, but this
+ * can be overridden by subclasses in order to support multiple suffixes.
+ *
+ * @return the resource suffixes; never {@code null} or empty
+ * @since 4.1
+ * @see #generateDefaultLocations(Class)
+ */
+ protected String[] getResourceSuffixes() {
+ return new String[] { getResourceSuffix() };
+ }
+
}
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java
index 1f12c29325..17f6a04a71 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java
@@ -35,26 +35,33 @@ import org.springframework.util.ObjectUtils;
* {@code AbstractDelegatingSmartContextLoader} serves as an abstract base class
* for implementations of the {@link SmartContextLoader} SPI that delegate to a
* set of candidate SmartContextLoaders (i.e., one that supports XML
- * configuration files and one that supports annotated classes) to determine which
- * context loader is appropriate for a given test class's configuration. Each
- * candidate is given a chance to {@link #processContextConfiguration process} the
+ * configuration files or Groovy scripts and one that supports annotated classes)
+ * to determine which context loader is appropriate for a given test class's
+ * configuration. Each candidate is given a chance to
+ * {@linkplain #processContextConfiguration process} the
* {@link ContextConfigurationAttributes} for each class in the test class hierarchy
* that is annotated with {@link ContextConfiguration @ContextConfiguration}, and
* the candidate that supports the merged, processed configuration will be used to
- * actually {@link #loadContext load} the context.
+ * actually {@linkplain #loadContext load} the context.
+ *
+ *
Any reference to an XML-based loader can be interpreted to mean
+ * a context loader that supports only XML configuration files or one that
+ * supports both XML configuration files and Groovy scripts simultaneously.
*
*
Placing an empty {@code @ContextConfiguration} annotation on a test class signals
- * that default resource locations (i.e., XML configuration files) or default
- * {@link org.springframework.context.annotation.Configuration configuration classes}
+ * that default resource locations (e.g., XML configuration files or Groovy scripts)
+ * or default
+ * {@linkplain org.springframework.context.annotation.Configuration configuration classes}
* should be detected. Furthermore, if a specific {@link ContextLoader} or
* {@link SmartContextLoader} is not explicitly declared via
* {@code @ContextConfiguration}, a concrete subclass of
* {@code AbstractDelegatingSmartContextLoader} will be used as the default loader,
- * thus providing automatic support for either XML configuration files or annotated
- * classes, but not both simultaneously.
+ * thus providing automatic support for either path-based resource locations
+ * (e.g., XML configuration files and Groovy scripts) or annotated classes,
+ * but not both simultaneously.
*
- *
As of Spring 3.2, a test class may optionally declare neither XML configuration
- * files nor annotated classes and instead declare only {@linkplain
+ *
As of Spring 3.2, a test class may optionally declare neither path-based
+ * resource locations nor annotated classes and instead declare only {@linkplain
* ContextConfiguration#initializers application context initializers}. In such
* cases, an attempt will still be made to detect defaults, but their absence will
* not result in an exception.
@@ -69,7 +76,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
/**
- * Get the delegate {@code SmartContextLoader} that supports XML configuration files.
+ * Get the delegate {@code SmartContextLoader} that supports XML configuration
+ * files and/or Groovy scripts.
*/
protected abstract SmartContextLoader getXmlLoader();
@@ -115,9 +123,9 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
* Delegates to candidate {@code SmartContextLoaders} to process the supplied
* {@link ContextConfigurationAttributes}.
*
Delegation is based on explicit knowledge of the implementations of the
- * default loaders for {@link #getXmlLoader() XML configuration files} and
- * {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
- * delegation algorithm is as follows:
+ * default loaders for {@linkplain #getXmlLoader() XML configuration files and
+ * Groovy scripts} and {@linkplain #getAnnotationConfigLoader() annotated classes}.
+ * Specifically, the delegation algorithm is as follows:
*
* - If the resource locations or annotated classes in the supplied
* {@code ContextConfigurationAttributes} are not empty, the appropriate
@@ -220,9 +228,9 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
* an {@link ApplicationContext}.
*
Delegation is based on explicit knowledge of the implementations of the
- * default loaders for {@link #getXmlLoader() XML configuration files} and
- * {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
- * delegation algorithm is as follows:
+ * default loaders for {@linkplain #getXmlLoader() XML configuration files and
+ * Groovy scripts} and {@linkplain #getAnnotationConfigLoader() annotated classes}.
+ * Specifically, the delegation algorithm is as follows:
*
* - If the resource locations in the supplied {@code MergedContextConfiguration}
* are not empty and the annotated classes are empty,
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java
index c3b63aef92..3beaac5ebc 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java
@@ -49,6 +49,8 @@ import org.springframework.util.ObjectUtils;
* @see #processContextConfiguration(ContextConfigurationAttributes)
* @see #detectDefaultConfigurationClasses(Class)
* @see #loadBeanDefinitions(GenericApplicationContext, MergedContextConfiguration)
+ * @see GenericXmlContextLoader
+ * @see GenericGroovyXmlContextLoader
*/
public class AnnotationConfigContextLoader extends AbstractGenericContextLoader {
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/DelegatingSmartContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/DelegatingSmartContextLoader.java
index 108c66f014..507438d149 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/DelegatingSmartContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/DelegatingSmartContextLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 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.
@@ -16,25 +16,55 @@
package org.springframework.test.context.support;
+import org.springframework.beans.BeanUtils;
import org.springframework.test.context.SmartContextLoader;
+import org.springframework.util.ClassUtils;
/**
* {@code DelegatingSmartContextLoader} is a concrete implementation of
* {@link AbstractDelegatingSmartContextLoader} that delegates to a
- * {@link GenericXmlContextLoader} and an {@link AnnotationConfigContextLoader}.
+ * {@link GenericXmlContextLoader} (or a {@link GenericGroovyXmlContextLoader} if Groovy
+ * is present in the classpath) and an {@link AnnotationConfigContextLoader}.
*
* @author Sam Brannen
* @since 3.1
* @see SmartContextLoader
* @see AbstractDelegatingSmartContextLoader
* @see GenericXmlContextLoader
+ * @see GenericGroovyXmlContextLoader
* @see AnnotationConfigContextLoader
*/
public class DelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
- private final SmartContextLoader xmlLoader = new GenericXmlContextLoader();
- private final SmartContextLoader annotationConfigLoader = new AnnotationConfigContextLoader();
+ private static final String GROOVY_XML_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.GenericGroovyXmlContextLoader";
+ private static final boolean groovyPresent = ClassUtils.isPresent("groovy.lang.Closure",
+ DelegatingSmartContextLoader.class.getClassLoader())
+ && ClassUtils.isPresent(GROOVY_XML_CONTEXT_LOADER_CLASS_NAME,
+ DelegatingSmartContextLoader.class.getClassLoader());
+
+ private final SmartContextLoader xmlLoader;
+ private final SmartContextLoader annotationConfigLoader;
+
+
+ public DelegatingSmartContextLoader() {
+ if (groovyPresent) {
+ try {
+ Class> loaderClass = ClassUtils.forName(GROOVY_XML_CONTEXT_LOADER_CLASS_NAME,
+ DelegatingSmartContextLoader.class.getClassLoader());
+ this.xmlLoader = (SmartContextLoader) BeanUtils.instantiateClass(loaderClass);
+ }
+ catch (Throwable ex) {
+ throw new IllegalStateException("Failed to enable support for Groovy scripts; "
+ + "could not load class: " + GROOVY_XML_CONTEXT_LOADER_CLASS_NAME, ex);
+ }
+ }
+ else {
+ this.xmlLoader = new GenericXmlContextLoader();
+ }
+
+ this.annotationConfigLoader = new AnnotationConfigContextLoader();
+ }
@Override
protected SmartContextLoader getXmlLoader() {
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/GenericGroovyXmlContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/GenericGroovyXmlContextLoader.java
new file mode 100644
index 0000000000..48f1f5661c
--- /dev/null
+++ b/spring-test/src/main/java/org/springframework/test/context/support/GenericGroovyXmlContextLoader.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.support;
+
+import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
+import org.springframework.beans.factory.support.BeanDefinitionReader;
+import org.springframework.context.support.GenericApplicationContext;
+
+/**
+ * Concrete implementation of {@link AbstractGenericContextLoader} that reads
+ * bean definitions from Groovy scripts and XML configuration files.
+ *
+ *
Default resource locations are detected using the suffixes
+ * {@code "-context.xml"} and {@code "Context.groovy"}.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ * @see GroovyBeanDefinitionReader
+ * @see GenericXmlContextLoader
+ * @see AnnotationConfigContextLoader
+ */
+public class GenericGroovyXmlContextLoader extends GenericXmlContextLoader {
+
+ /**
+ * Create a new {@link GroovyBeanDefinitionReader}.
+ * @return a new {@code GroovyBeanDefinitionReader}
+ */
+ @Override
+ protected BeanDefinitionReader createBeanDefinitionReader(final GenericApplicationContext context) {
+ return new GroovyBeanDefinitionReader(context);
+ }
+
+ /**
+ * Returns {@code "-context.xml" and "Context.groovy"} in order to
+ * support detection of a default XML config file or Groovy script.
+ */
+ @Override
+ protected String[] getResourceSuffixes() {
+ return new String[] { super.getResourceSuffix(), "Context.groovy" };
+ }
+
+ /**
+ * {@code GenericGroovyXmlContextLoader} supports both Groovy and XML
+ * resource types for detection of defaults. Consequently, this method
+ * is not supported.
+ * @see #getResourceSuffixes()
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ protected String getResourceSuffix() {
+ throw new UnsupportedOperationException(
+ "GenericGroovyXmlContextLoader does not support the getResourceSuffix() method");
+ }
+
+}
diff --git a/spring-test/src/main/java/org/springframework/test/context/support/GenericXmlContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/GenericXmlContextLoader.java
index 0e43bec0e9..48c1bc0dab 100644
--- a/spring-test/src/main/java/org/springframework/test/context/support/GenericXmlContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/support/GenericXmlContextLoader.java
@@ -26,23 +26,29 @@ import org.springframework.util.ObjectUtils;
* Concrete implementation of {@link AbstractGenericContextLoader} that reads
* bean definitions from XML resources.
*
+ *
Default resource locations are detected using the suffix
+ * {@code "-context.xml"}.
+ *
* @author Sam Brannen
* @since 2.5
+ * @see XmlBeanDefinitionReader
+ * @see GenericGroovyXmlContextLoader
+ * @see AnnotationConfigContextLoader
*/
public class GenericXmlContextLoader extends AbstractGenericContextLoader {
/**
* Create a new {@link XmlBeanDefinitionReader}.
- * @return a new XmlBeanDefinitionReader
- * @see XmlBeanDefinitionReader
+ * @return a new {@code XmlBeanDefinitionReader}
*/
@Override
- protected BeanDefinitionReader createBeanDefinitionReader(final GenericApplicationContext context) {
+ protected BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {
return new XmlBeanDefinitionReader(context);
}
/**
- * Returns "{@code -context.xml}".
+ * Returns {@code "-context.xml"} in order to support detection of a
+ * default XML config file.
*/
@Override
protected String getResourceSuffix() {
diff --git a/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java
index 940b11bdcc..fe99a0222a 100644
--- a/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/web/AnnotationConfigWebContextLoader.java
@@ -50,6 +50,8 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
* @see #processContextConfiguration(ContextConfigurationAttributes)
* @see #detectDefaultConfigurationClasses(Class)
* @see #loadBeanDefinitions(GenericWebApplicationContext, WebMergedContextConfiguration)
+ * @see GenericXmlWebContextLoader
+ * @see GenericGroovyXmlWebContextLoader
*/
public class AnnotationConfigWebContextLoader extends AbstractGenericWebContextLoader {
diff --git a/spring-test/src/main/java/org/springframework/test/context/web/GenericGroovyXmlWebContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/web/GenericGroovyXmlWebContextLoader.java
new file mode 100644
index 0000000000..8c1924e616
--- /dev/null
+++ b/spring-test/src/main/java/org/springframework/test/context/web/GenericGroovyXmlWebContextLoader.java
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.web;
+
+import org.springframework.beans.factory.groovy.GroovyBeanDefinitionReader;
+import org.springframework.web.context.support.GenericWebApplicationContext;
+
+/**
+ * Concrete implementation of {@link AbstractGenericWebContextLoader} that loads
+ * bean definitions from Groovy scripts and XML configuration files.
+ *
+ *
Default resource locations are detected using the suffixes
+ * {@code "-context.xml"} and {@code "Context.groovy"}.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ * @see GroovyBeanDefinitionReader
+ * @see GenericXmlWebContextLoader
+ * @see AnnotationConfigWebContextLoader
+ */
+public class GenericGroovyXmlWebContextLoader extends GenericXmlWebContextLoader {
+
+ /**
+ * Loads bean definitions using a {@link GroovyBeanDefinitionReader}.
+ * @see AbstractGenericWebContextLoader#loadBeanDefinitions
+ */
+ @Override
+ protected void loadBeanDefinitions(GenericWebApplicationContext context,
+ WebMergedContextConfiguration webMergedConfig) {
+ new GroovyBeanDefinitionReader(context).loadBeanDefinitions(webMergedConfig.getLocations());
+ }
+
+ /**
+ * Returns {@code "-context.xml" and "Context.groovy"} in order to
+ * support detection of a default XML config file or Groovy script.
+ */
+ @Override
+ protected String[] getResourceSuffixes() {
+ return new String[] { super.getResourceSuffix(), "Context.groovy" };
+ }
+
+ /**
+ * {@code GenericGroovyXmlWebContextLoader} supports both Groovy and XML
+ * resource types for detection of defaults. Consequently, this method
+ * is not supported.
+ * @see #getResourceSuffixes()
+ * @throws UnsupportedOperationException
+ */
+ @Override
+ protected String getResourceSuffix() {
+ throw new UnsupportedOperationException(
+ "GenericGroovyXmlWebContextLoader does not support the getResourceSuffix() method");
+ }
+
+}
diff --git a/spring-test/src/main/java/org/springframework/test/context/web/GenericXmlWebContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/web/GenericXmlWebContextLoader.java
index a704ec3b0a..2d39c303ed 100644
--- a/spring-test/src/main/java/org/springframework/test/context/web/GenericXmlWebContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/web/GenericXmlWebContextLoader.java
@@ -25,8 +25,13 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
* Concrete implementation of {@link AbstractGenericWebContextLoader} that loads
* bean definitions from XML resources.
*
+ *
Default resource locations are detected using the suffix
+ * {@code "-context.xml"}.
+ *
* @author Sam Brannen
* @since 3.2
+ * @see GenericGroovyXmlWebContextLoader
+ * @see AnnotationConfigWebContextLoader
*/
public class GenericXmlWebContextLoader extends AbstractGenericWebContextLoader {
@@ -41,7 +46,8 @@ public class GenericXmlWebContextLoader extends AbstractGenericWebContextLoader
}
/**
- * Returns "{@code -context.xml}".
+ * Returns {@code "-context.xml"} in order to support detection of a
+ * default XML config file.
*/
@Override
protected String getResourceSuffix() {
diff --git a/spring-test/src/main/java/org/springframework/test/context/web/WebDelegatingSmartContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/web/WebDelegatingSmartContextLoader.java
index 9dc43968aa..ff353ae15a 100644
--- a/spring-test/src/main/java/org/springframework/test/context/web/WebDelegatingSmartContextLoader.java
+++ b/spring-test/src/main/java/org/springframework/test/context/web/WebDelegatingSmartContextLoader.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2012 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.
@@ -16,13 +16,16 @@
package org.springframework.test.context.web;
+import org.springframework.beans.BeanUtils;
import org.springframework.test.context.SmartContextLoader;
import org.springframework.test.context.support.AbstractDelegatingSmartContextLoader;
+import org.springframework.util.ClassUtils;
/**
* {@code WebDelegatingSmartContextLoader} is a concrete implementation of
* {@link AbstractDelegatingSmartContextLoader} that delegates to a
- * {@link GenericXmlWebContextLoader} and an {@link AnnotationConfigWebContextLoader}.
+ * {@link GenericXmlWebContextLoader} (or a {@link GenericGroovyXmlWebContextLoader} if
+ * Groovy is present on the classpath) and an {@link AnnotationConfigWebContextLoader}.
*
* @author Sam Brannen
* @since 3.2
@@ -33,9 +36,35 @@ import org.springframework.test.context.support.AbstractDelegatingSmartContextLo
*/
public class WebDelegatingSmartContextLoader extends AbstractDelegatingSmartContextLoader {
- private final SmartContextLoader xmlLoader = new GenericXmlWebContextLoader();
- private final SmartContextLoader annotationConfigLoader = new AnnotationConfigWebContextLoader();
+ private static final String GROOVY_XML_WEB_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.web.GenericGroovyXmlWebContextLoader";
+ private static final boolean groovyPresent = ClassUtils.isPresent("groovy.lang.Closure",
+ WebDelegatingSmartContextLoader.class.getClassLoader())
+ && ClassUtils.isPresent(GROOVY_XML_WEB_CONTEXT_LOADER_CLASS_NAME,
+ WebDelegatingSmartContextLoader.class.getClassLoader());
+
+ private final SmartContextLoader xmlLoader;
+ private final SmartContextLoader annotationConfigLoader;
+
+
+ public WebDelegatingSmartContextLoader() {
+ if (groovyPresent) {
+ try {
+ Class> loaderClass = ClassUtils.forName(GROOVY_XML_WEB_CONTEXT_LOADER_CLASS_NAME,
+ WebDelegatingSmartContextLoader.class.getClassLoader());
+ this.xmlLoader = (SmartContextLoader) BeanUtils.instantiateClass(loaderClass);
+ }
+ catch (Throwable ex) {
+ throw new IllegalStateException("Failed to enable support for Groovy scripts; "
+ + "could not load class: " + GROOVY_XML_WEB_CONTEXT_LOADER_CLASS_NAME, ex);
+ }
+ }
+ else {
+ this.xmlLoader = new GenericXmlWebContextLoader();
+ }
+
+ this.annotationConfigLoader = new AnnotationConfigWebContextLoader();
+ }
@Override
protected SmartContextLoader getXmlLoader() {
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/AbsolutePathGroovySpringContextTests.java b/spring-test/src/test/java/org/springframework/test/context/groovy/AbsolutePathGroovySpringContextTests.java
new file mode 100644
index 0000000000..e7114e2d51
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/AbsolutePathGroovySpringContextTests.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy;
+
+import org.springframework.test.context.ContextConfiguration;
+
+/**
+ * Extension of {@link GroovySpringContextTests} that declares a Groovy
+ * script using an absolute path.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ * @see GroovySpringContextTests
+ * @see RelativePathGroovySpringContextTests
+ */
+@ContextConfiguration(locations = "/org/springframework/test/context/groovy/context.groovy", inheritLocations = false)
+public class AbsolutePathGroovySpringContextTests extends GroovySpringContextTests {
+
+ /* all tests are in the superclass */
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionGroovySpringContextTests.java b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionGroovySpringContextTests.java
new file mode 100644
index 0000000000..d2c7c092b6
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionGroovySpringContextTests.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.tests.sample.beans.Employee;
+import org.springframework.tests.sample.beans.Pet;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration test class that verifies proper detection of a default
+ * Groovy script (as opposed to a default XML config file).
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ * @see DefaultScriptDetectionGroovySpringContextTestsContext
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+// Config loaded from DefaultScriptDetectionGroovySpringContextTestsContext.groovy
+@ContextConfiguration
+public class DefaultScriptDetectionGroovySpringContextTests {
+
+ @Autowired
+ private Employee employee;
+
+ @Autowired
+ private Pet pet;
+
+ @Autowired
+ protected String foo;
+
+
+ @Test
+ public final void verifyAnnotationAutowiredFields() {
+ assertNotNull("The employee field should have been autowired.", this.employee);
+ assertEquals("Dilbert", this.employee.getName());
+
+ assertNotNull("The pet field should have been autowired.", this.pet);
+ assertEquals("Dogbert", this.pet.getName());
+
+ assertEquals("The foo field should have been autowired.", "Foo", this.foo);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionGroovySpringContextTestsContext.groovy b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionGroovySpringContextTestsContext.groovy
new file mode 100644
index 0000000000..f584d6e40b
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionGroovySpringContextTestsContext.groovy
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy
+
+import org.springframework.tests.sample.beans.Employee;
+import org.springframework.tests.sample.beans.Pet;
+
+/**
+ * Groovy script for defining Spring beans for integration tests.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+beans {
+
+ foo String, 'Foo'
+ bar String, 'Bar'
+
+ employee(Employee) {
+ name = "Dilbert"
+ age = 42
+ company = "???"
+ }
+
+ pet(Pet, 'Dogbert')
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTests-context.xml b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTests-context.xml
new file mode 100644
index 0000000000..5df70bcfcb
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTests-context.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTests.java b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTests.java
new file mode 100644
index 0000000000..828cd8bae5
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTests.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration test class that verifies proper detection of a default
+ * XML config file even though a suitable Groovy script exists.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+public class DefaultScriptDetectionXmlSupersedesGroovySpringContextTests {
+
+ @Autowired
+ protected String foo;
+
+
+ @Test
+ public final void foo() {
+ assertEquals("The foo field should have been autowired.", "Foo", this.foo);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTestsContext.groovy b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTestsContext.groovy
new file mode 100644
index 0000000000..b55405b6e5
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/DefaultScriptDetectionXmlSupersedesGroovySpringContextTestsContext.groovy
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy
+
+/**
+ * This is intentionally an empty config file, since the XML file should
+ * be picked up as the default before a Groovy script.
+ *
+ *
See: {@code DefaultScriptDetectionXmlSupersedesGroovySpringContextTests-context.xml}
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+beans {
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/GroovyControlGroupTests.java b/spring-test/src/test/java/org/springframework/test/context/groovy/GroovyControlGroupTests.java
new file mode 100644
index 0000000000..e3c5fdf4b4
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/GroovyControlGroupTests.java
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy;
+
+import org.junit.Test;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.GenericGroovyApplicationContext;
+import org.springframework.tests.sample.beans.Employee;
+import org.springframework.tests.sample.beans.Pet;
+
+import static org.junit.Assert.*;
+
+/**
+ * Simple integration test to verify the expected functionality of
+ * {@link GenericGroovyApplicationContext}, thereby validating the proper
+ * syntax and configuration of {@code "context.groovy"} without using the
+ * Spring TestContext Framework.
+ *
+ *
In other words, this test class serves merely as a control group
+ * to ensure that there is nothing wrong with the Groovy script used by
+ * other tests in this package.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+public class GroovyControlGroupTests {
+
+ @Test
+ @SuppressWarnings("resource")
+ public void verifyScriptUsingGenericGroovyApplicationContext() {
+ ApplicationContext ctx = new GenericGroovyApplicationContext(getClass(), "context.groovy");
+
+ String foo = ctx.getBean("foo", String.class);
+ assertEquals("Foo", foo);
+
+ String bar = ctx.getBean("bar", String.class);
+ assertEquals("Bar", bar);
+
+ Pet pet = ctx.getBean(Pet.class);
+ assertNotNull("pet", pet);
+ assertEquals("Dogbert", pet.getName());
+
+ Employee employee = ctx.getBean(Employee.class);
+ assertNotNull("employee", employee);
+ assertEquals("Dilbert", employee.getName());
+ assertEquals("???", employee.getCompany());
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/GroovySpringContextTests.java b/spring-test/src/test/java/org/springframework/test/context/groovy/GroovySpringContextTests.java
new file mode 100644
index 0000000000..fc5361242d
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/GroovySpringContextTests.java
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy;
+
+import javax.annotation.Resource;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.BeanNameAware;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.tests.sample.beans.Employee;
+import org.springframework.tests.sample.beans.Pet;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration tests for loading an {@code ApplicationContext} from a
+ * Groovy script with the TestContext framework.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration("context.groovy")
+public class GroovySpringContextTests implements BeanNameAware, InitializingBean {
+
+ private boolean beanInitialized = false;
+
+ private String beanName = "replace me with [" + getClass().getName() + "]";
+
+ @Autowired
+ private ApplicationContext applicationContext;
+
+ private Employee employee;
+
+ @Autowired
+ private Pet pet;
+
+ @Autowired(required = false)
+ protected Long nonrequiredLong;
+
+ @Resource
+ protected String foo;
+
+ protected String bar;
+
+
+ @Autowired
+ protected final void setEmployee(final Employee employee) {
+ this.employee = employee;
+ }
+
+ @Resource
+ protected final void setBar(final String bar) {
+ this.bar = bar;
+ }
+
+ @Override
+ public final void setBeanName(final String beanName) {
+ this.beanName = beanName;
+ }
+
+ @Override
+ public final void afterPropertiesSet() throws Exception {
+ this.beanInitialized = true;
+ }
+
+ @Test
+ public final void verifyBeanInitialized() {
+ assertTrue("This test bean should have been initialized due to InitializingBean semantics.",
+ this.beanInitialized);
+ }
+
+ @Test
+ public final void verifyBeanNameSet() {
+ assertEquals("The bean name of this test instance should have been set to the fully qualified class name "
+ + "due to BeanNameAware semantics.", getClass().getName(), this.beanName);
+ }
+
+ @Test
+ public final void verifyAnnotationAutowiredFields() {
+ assertNull("The nonrequiredLong property should NOT have been autowired.", this.nonrequiredLong);
+ assertNotNull("The application context should have been autowired.", this.applicationContext);
+ assertNotNull("The pet field should have been autowired.", this.pet);
+ assertEquals("Dogbert", this.pet.getName());
+ }
+
+ @Test
+ public final void verifyAnnotationAutowiredMethods() {
+ assertNotNull("The employee setter method should have been autowired.", this.employee);
+ assertEquals("Dilbert", this.employee.getName());
+ }
+
+ @Test
+ public final void verifyResourceAnnotationWiredFields() {
+ assertEquals("The foo field should have been wired via @Resource.", "Foo", this.foo);
+ }
+
+ @Test
+ public final void verifyResourceAnnotationWiredMethods() {
+ assertEquals("The bar method should have been wired via @Resource.", "Bar", this.bar);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/MixedXmlAndGroovySpringContextTests.java b/spring-test/src/test/java/org/springframework/test/context/groovy/MixedXmlAndGroovySpringContextTests.java
new file mode 100644
index 0000000000..f064e3bc75
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/MixedXmlAndGroovySpringContextTests.java
@@ -0,0 +1,66 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.tests.sample.beans.Employee;
+import org.springframework.tests.sample.beans.Pet;
+
+import static org.junit.Assert.*;
+
+/**
+ * Integration test class that verifies proper support for mixing XML
+ * configuration files and Groovy scripts to load an {@code ApplicationContext}
+ * using the TestContext framework.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration({ "contextA.groovy", "contextB.xml" })
+public class MixedXmlAndGroovySpringContextTests {
+
+ @Autowired
+ private Employee employee;
+
+ @Autowired
+ private Pet pet;
+
+ @Autowired
+ protected String foo;
+
+ @Autowired
+ protected String bar;
+
+
+ @Test
+ public final void verifyAnnotationAutowiredFields() {
+ assertNotNull("The employee field should have been autowired.", this.employee);
+ assertEquals("Dilbert", this.employee.getName());
+
+ assertNotNull("The pet field should have been autowired.", this.pet);
+ assertEquals("Dogbert", this.pet.getName());
+
+ assertEquals("The foo field should have been autowired.", "Groovy Foo", this.foo);
+ assertEquals("The bar field should have been autowired.", "XML Bar", this.bar);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/RelativePathGroovySpringContextTests.java b/spring-test/src/test/java/org/springframework/test/context/groovy/RelativePathGroovySpringContextTests.java
new file mode 100644
index 0000000000..f621df8160
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/RelativePathGroovySpringContextTests.java
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy;
+
+import org.springframework.test.context.ContextConfiguration;
+
+/**
+ * Extension of {@link GroovySpringContextTests} that declares a Groovy
+ * script using a relative path.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ * @see GroovySpringContextTests
+ * @see AbsolutePathGroovySpringContextTests
+ */
+@ContextConfiguration(locations = "../groovy/context.groovy", inheritLocations = false)
+public class RelativePathGroovySpringContextTests extends GroovySpringContextTests {
+
+ /* all tests are in the superclass */
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/context.groovy b/spring-test/src/test/java/org/springframework/test/context/groovy/context.groovy
new file mode 100644
index 0000000000..f584d6e40b
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/context.groovy
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy
+
+import org.springframework.tests.sample.beans.Employee;
+import org.springframework.tests.sample.beans.Pet;
+
+/**
+ * Groovy script for defining Spring beans for integration tests.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+beans {
+
+ foo String, 'Foo'
+ bar String, 'Bar'
+
+ employee(Employee) {
+ name = "Dilbert"
+ age = 42
+ company = "???"
+ }
+
+ pet(Pet, 'Dogbert')
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/contextA.groovy b/spring-test/src/test/java/org/springframework/test/context/groovy/contextA.groovy
new file mode 100644
index 0000000000..c2d887fe55
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/contextA.groovy
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.groovy
+
+/**
+ * Groovy script for defining Spring beans for integration tests.
+ *
+ * @author Sam Brannen
+ * @since 4.1
+ */
+beans {
+
+ foo String, 'Groovy Foo'
+ bar String, 'Groovy Bar'
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/groovy/contextB.xml b/spring-test/src/test/java/org/springframework/test/context/groovy/contextB.xml
new file mode 100644
index 0000000000..989815a91d
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/groovy/contextB.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-test/src/test/java/org/springframework/test/context/web/BasicGroovyWacTests.java b/spring-test/src/test/java/org/springframework/test/context/web/BasicGroovyWacTests.java
new file mode 100644
index 0000000000..1403109257
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/web/BasicGroovyWacTests.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ * 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.
+ */
+
+package org.springframework.test.context.web;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.springframework.test.context.ContextConfiguration;
+
+/**
+ * @author Sam Brannen
+ * @since 4.1
+ * @see BasicXmlWacTests
+ */
+// Config loaded from BasicGroovyWacTestsContext.groovy
+@ContextConfiguration
+public class BasicGroovyWacTests extends AbstractBasicWacTests {
+
+ @Test
+ public void groovyFooAutowired() {
+ assertEquals("Groovy Foo", foo);
+ }
+
+}
diff --git a/spring-test/src/test/java/org/springframework/test/context/web/BasicGroovyWacTestsContext.groovy b/spring-test/src/test/java/org/springframework/test/context/web/BasicGroovyWacTestsContext.groovy
new file mode 100644
index 0000000000..dcb7f12fe9
--- /dev/null
+++ b/spring-test/src/test/java/org/springframework/test/context/web/BasicGroovyWacTestsContext.groovy
@@ -0,0 +1,3 @@
+package org.springframework.test.context.web
+
+beans { foo String, 'Groovy Foo' }
\ No newline at end of file
diff --git a/spring-test/src/test/resources/log4j.properties b/spring-test/src/test/resources/log4j.properties
index 5947420f13..186db8da23 100644
--- a/spring-test/src/test/resources/log4j.properties
+++ b/spring-test/src/test/resources/log4j.properties
@@ -1,6 +1,6 @@
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
-log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%c] - %m%n
+log4j.appender.console.layout.ConversionPattern=%d{HH:mm:ss,SSS} [%-5p] [%c] - %m%n
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.file=build/spring-test.log
@@ -16,6 +16,7 @@ log4j.logger.org.springframework.test.context.transaction.TransactionalTestExecu
log4j.logger.org.springframework.test.context.web=WARN
log4j.logger.org.springframework.test.context=WARN
+#log4j.logger.org.springframework.test.context.support=INFO
#log4j.logger.org.springframework.test.context.support.DelegatingSmartContextLoader=INFO
#log4j.logger.org.springframework.test.context.support.AbstractGenericContextLoader=INFO
#log4j.logger.org.springframework.test.context.support.AnnotationConfigContextLoader=INFO