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+ + ++ + + + + ++ + + ++