diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java b/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java index ee062096fa..341e327936 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/support/AbstractContextLoader.java @@ -16,7 +16,10 @@ package org.springframework.test.context.support; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.support.ResourcePatternUtils; import org.springframework.test.context.ContextConfigurationAttributes; import org.springframework.test.context.ContextLoader; @@ -29,9 +32,16 @@ import org.springframework.util.StringUtils; /** * Abstract application context loader, which provides a basis for all concrete - * implementations of the {@link ContextLoader} strategy. Provides a + * implementations of the {@link ContextLoader} SPI. Provides a * Template Method based approach for {@link #processLocations processing} - * locations. + * resource locations. + * + *
As of Spring 3.1, AbstractContextLoader
also provides a basis
+ * for all concrete implementations of the {@link SmartContextLoader} SPI. For
+ * backwards compatibility with the {@code ContextLoader} SPI,
+ * {@link #processContextConfiguration()} delegates to
+ * {@link #processLocations()}, and {@link #generatesDefaults()} delegates to
+ * {@link #isGenerateDefaultLocations()}.
*
* @author Sam Brannen
* @author Juergen Hoeller
@@ -41,14 +51,18 @@ import org.springframework.util.StringUtils;
*/
public abstract class AbstractContextLoader implements SmartContextLoader {
+ private static final Log logger = LogFactory.getLog(AbstractContextLoader.class);
+
+ private static final String[] EMPTY_STRING_ARRAY = new String[] {};
private static final String SLASH = "/";
// --- SmartContextLoader -----------------------------------------------
/**
- * TODO Document generatesDefaults() implementation.
- *
+ * For backwards compatibility with the {@link ContextLoader} SPI, the
+ * default implementation simply delegates to
+ * {@link #isGenerateDefaultLocations()}.
* @see org.springframework.test.context.SmartContextLoader#generatesDefaults()
* @see #isGenerateDefaultLocations()
*/
@@ -57,14 +71,22 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
}
/**
- * TODO Document processContextConfiguration() implementation.
- *
- * @see #processLocations(Class, String...)
+ * For backwards compatibility with the {@link ContextLoader} SPI, the
+ * default implementation simply delegates to {@link #processLocations()},
+ * passing it the {@link ContextConfigurationAttributes#getDeclaringClass()
+ * declaring class} and {@link ContextConfigurationAttributes#getLocations()
+ * resource locations} retrieved from the supplied
+ * {@link ContextConfigurationAttributes configuration attributes}. The
+ * processed locations are then
+ * {@link ContextConfigurationAttributes#setLocations(String[]) set} in
+ * the supplied configuration attributes.
+ *
Can be overridden in subclasses — for example, to process
+ * configuration classes instead of resource locations.
+ * @see #processLocations()
*/
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
String[] processedLocations = processLocations(configAttributes.getDeclaringClass(),
configAttributes.getLocations());
-
configAttributes.setLocations(processedLocations);
}
@@ -72,7 +94,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
/**
* If the supplied locations
are null
or
- * empty and {@link #isGenerateDefaultLocations()} is
+ * empty and {@link #isGenerateDefaultLocations()} returns
* true
, default locations will be
* {@link #generateDefaultLocations(Class) generated} for the specified
* {@link Class class} and the configured
@@ -83,10 +105,12 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
* used when generating default locations
* @param locations the unmodified locations to use for loading the
* application context (can be null
or empty)
- * @return an array of application context resource locations
- * @see #generateDefaultLocations
- * @see #modifyLocations
- * @see org.springframework.test.context.ContextLoader#processLocations
+ * @return a processed array of application context resource locations
+ * @see #isGenerateDefaultLocations()
+ * @see #generateDefaultLocations()
+ * @see #modifyLocations()
+ * @see org.springframework.test.context.ContextLoader#processLocations()
+ * @see #processContextConfiguration()
*/
public final String[] processLocations(Class> clazz, String... locations) {
return (ObjectUtils.isEmpty(locations) && isGenerateDefaultLocations()) ? generateDefaultLocations(clazz)
@@ -101,6 +125,11 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
* "classpath:/com/example/MyTest<suffix>
",
* where <suffix>
is the value of the
* {@link #getResourceSuffix() resource suffix} string.
+ *
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
@@ -111,12 +140,17 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
Assert.notNull(clazz, "Class must not be null");
String suffix = getResourceSuffix();
Assert.hasText(suffix, "Resource suffix must not be empty");
+ String resourcePath = SLASH + ClassUtils.convertClassNameToResourcePath(clazz.getName()) + suffix;
+
+ if (!new ClassPathResource(resourcePath, clazz).exists()) {
+ logger.warn(String.format(
+ "Cannot generate default resource location for test class [%s]: classpath resource [%s] does not exist.",
+ clazz.getName(), resourcePath));
+ return EMPTY_STRING_ARRAY;
+ }
- // TODO Adhere to SmartContextLoader contract: verify existence of
- // default and return an empty array if non-existent, in which case a
- // warning should be logged as well.
- return new String[] { ResourceUtils.CLASSPATH_URL_PREFIX + SLASH
- + ClassUtils.convertClassNameToResourcePath(clazz.getName()) + suffix };
+ // else
+ return new String[] { ResourceUtils.CLASSPATH_URL_PREFIX + resourcePath };
}
/**
@@ -157,8 +191,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
/**
* Determine whether or not default resource locations should be
* generated if the locations
provided to
- * {@link #processLocations(Class,String...) processLocations()} are
- * null
or empty.
+ * {@link #processLocations()} are null
or empty.
*
Can be overridden by subclasses to change the default behavior.
* @return always true
by default
*/
@@ -171,7 +204,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
* locations when generating default locations.
*
Must be implemented by subclasses.
* @return the resource suffix; should not be null
or empty
- * @see #generateDefaultLocations(Class)
+ * @see #generateDefaultLocations()
*/
protected abstract String getResourceSuffix();
diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java b/org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java
index d000b4f921..4943a35a23 100644
--- a/org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java
+++ b/org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java
@@ -63,7 +63,7 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
/**
* TODO Document overridden processContextConfiguration().
*
- * @see org.springframework.test.context.SmartContextLoader#processContextConfiguration
+ * @see org.springframework.test.context.SmartContextLoader#processContextConfiguration()
* @see #generatesDefaults
* @see #generateDefaultConfigurationClasses
*/
@@ -102,7 +102,20 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
}
/**
- * TODO Document generateDefaultConfigurationClasses().
+ * TODO Complete JavaDoc for generateDefaultConfigurationClasses().
+ *
+ *
The implementation of this method adheres to the contract defined in the
+ * {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
+ * SPI. Specifically, this method will preemptively verify that the
+ * generated default configuration classes exist and that such classes
+ * comply with the constraints required of {@link Configuration @Configuration}
+ * class implementations. If a candidate configuration class does meet these
+ * requirements, this method will log a warning and potentially return an empty
+ * array.
+ *
+ * @param declaringClass the test class that declared
+ * {@link org.springframework.test.context.ContextConfiguration @ContextConfiguration}
+ * @return
*/
protected Class>[] generateDefaultConfigurationClasses(Class> declaringClass) {
Assert.notNull(declaringClass, "Declaring class must not be null");
diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests$BareAnnotations-context.xml b/org.springframework.test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests$BareAnnotations-context.xml
new file mode 100644
index 0000000000..44d110480d
--- /dev/null
+++ b/org.springframework.test/src/test/java/org/springframework/test/context/ContextLoaderUtilsTests$BareAnnotations-context.xml
@@ -0,0 +1,7 @@
+
+