[SPR-5916] ContextLoader class is now inherited from class hierarchy if not specified explicitly via @ContextConfiguration's loader attribute on the current test class.

This commit is contained in:
Sam Brannen
2009-07-20 09:35:33 +00:00
parent 7f3c4cec25
commit fc79d98b6a
6 changed files with 215 additions and 22 deletions

View File

@@ -87,6 +87,10 @@ public @interface ContextConfiguration {
/**
* The type of {@link ContextLoader} to use for loading an
* {@link org.springframework.context.ApplicationContext ApplicationContext}.
* <p>If not specified, the loader will be inherited from the first superclass
* which is annotated with <code>&#064;ContextConfiguration</code> and specifies
* an explicit loader. If no class in the hierarchy specifies an explicit
* loader, a default loader will be used instead.
*/
Class<? extends ContextLoader> loader() default ContextLoader.class;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2008 the original author or authors.
* Copyright 2002-2009 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.
@@ -95,7 +95,6 @@ public class TestContext extends AttributeAccessorSupport {
* @param defaultContextLoaderClassName the name of the default
* <code>ContextLoader</code> class to use (may be <code>null</code>)
*/
@SuppressWarnings("unchecked")
TestContext(Class<?> testClass, ContextCache contextCache, String defaultContextLoaderClassName) {
Assert.notNull(testClass, "Test class must not be null");
Assert.notNull(contextCache, "ContextCache must not be null");
@@ -119,23 +118,8 @@ public class TestContext extends AttributeAccessorSupport {
+ "]");
}
Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader();
if (ContextLoader.class.equals(contextLoaderClass)) {
try {
if (logger.isTraceEnabled()) {
logger.trace("Using default ContextLoader class [" + defaultContextLoaderClassName
+ "] for @ContextConfiguration [" + contextConfiguration + "] and class [" + testClass
+ "]");
}
contextLoaderClass = (Class<? extends ContextLoader>) getClass().getClassLoader().loadClass(
defaultContextLoaderClassName);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Could not load default ContextLoader class ["
+ defaultContextLoaderClassName + "]. Specify @ContextConfiguration's 'loader' "
+ "attribute or make the default loader class available.");
}
}
Class<? extends ContextLoader> contextLoaderClass = retrieveContextLoaderClass(testClass,
defaultContextLoaderClassName);
contextLoader = (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass);
locations = retrieveContextLocations(contextLoader, testClass);
}
@@ -146,6 +130,80 @@ public class TestContext extends AttributeAccessorSupport {
this.locations = locations;
}
/**
* <p>
* Retrieve the {@link ContextLoader} {@link Class} to use for the supplied
* {@link Class test class}.
* <ol>
* <li>If the {@link ContextConfiguration#loader() loader} attribute of
* {@link ContextConfiguration &#064;ContextConfiguration} is configured
* with an explicit class, that class will be returned.</li>
* <li>If a <code>loader</code> class is not specified, the class hierarchy
* will be traversed to find a parent class annotated with
* <code>&#064;ContextConfiguration</code>; go to step #1.</li>
* </ol>
* <p>
* If no explicit <code>loader</code> class is found after traversing the
* class hierarchy, an attempt will be made to load and return the class
* with the supplied <code>defaultContextLoaderClassName</code>.
*
* @param clazz the class for which to retrieve <code>ContextLoader</code>
* class; must not be <code>null</code>
* @param defaultContextLoaderClassName the name of the default
* <code>ContextLoader</code> class to use; must not be <code>null</code> or
* empty
* @return the <code>ContextLoader</code> class to use for the specified
* class
* @throws IllegalArgumentException if {@link ContextConfiguration
* &#064;ContextConfiguration} is not <em>present</em> on the supplied class
*/
@SuppressWarnings("unchecked")
private Class<? extends ContextLoader> retrieveContextLoaderClass(Class<?> clazz,
String defaultContextLoaderClassName) {
Assert.notNull(clazz, "Class must not be null");
Assert.hasText(defaultContextLoaderClassName, "Default ContextLoader class name must not be null or empty");
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
Assert.notNull(declaringClass, "Could not find an 'annotation declaring class' for annotation type ["
+ annotationType + "] and class [" + clazz + "]");
while (declaringClass != null) {
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
if (logger.isTraceEnabled()) {
logger.trace("Processing ContextLoader for @ContextConfiguration [" + contextConfiguration
+ "] and declaring class [" + declaringClass + "]");
}
Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader();
if (!ContextLoader.class.equals(contextLoaderClass)) {
if (logger.isDebugEnabled()) {
logger.debug("Found explicit ContextLoader [" + contextLoaderClass
+ "] for @ContextConfiguration [" + contextConfiguration + "] and declaring class ["
+ declaringClass + "]");
}
return contextLoaderClass;
}
declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType,
declaringClass.getSuperclass());
}
try {
ContextConfiguration contextConfiguration = clazz.getAnnotation(ContextConfiguration.class);
if (logger.isTraceEnabled()) {
logger.trace("Using default ContextLoader class [" + defaultContextLoaderClassName
+ "] for @ContextConfiguration [" + contextConfiguration + "] and class [" + clazz + "]");
}
return (Class<? extends ContextLoader>) getClass().getClassLoader().loadClass(defaultContextLoaderClassName);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Could not load default ContextLoader class ["
+ defaultContextLoaderClassName + "]. Specify @ContextConfiguration's 'loader' "
+ "attribute or make the default loader class available.");
}
}
/**
* Retrieve {@link ApplicationContext} resource locations for the supplied
* {@link Class class}, using the supplied {@link ContextLoader} to
@@ -157,10 +215,10 @@ public class TestContext extends AttributeAccessorSupport {
* &#064;ContextConfiguration} will be taken into consideration.
* Specifically, if the <code>inheritLocations</code> flag is set to
* <code>true</code>, locations defined in the annotated class will be
* appended to the locations defined in superclasses. &#064;param
* contextLoader the ContextLoader to use for processing the locations (must
* not be <code>null</code>)
* appended to the locations defined in superclasses.
*
* @param contextLoader the ContextLoader to use for processing the
* locations (must not be <code>null</code>)
* @param clazz the class for which to retrieve the resource locations (must
* not be <code>null</code>)
* @return the list of ApplicationContext resource locations for the