Browse Source

[SPR-8386] ContextLoader resolution once again ignores the inheritLocations flag on @ContextConfiguration.

pull/7/head
Sam Brannen 14 years ago
parent
commit
2b5d2e5a0a
  1. 193
      org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java

193
org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java

@ -56,63 +56,10 @@ abstract class ContextLoaderUtils { @@ -56,63 +56,10 @@ abstract class ContextLoaderUtils {
/* no-op */
}
/**
* Resolve the list of {@link ContextConfigurationAttributes configuration
* attributes} for the supplied {@link Class class} and its superclasses.
* <p>Note that the {@link ContextConfiguration#inheritLocations
* inheritLocations} flag of {@link ContextConfiguration
* &#064;ContextConfiguration} will be taken into consideration.
* Specifically, if the <code>inheritLocations</code> flag is set to
* <code>true</code>, configuration attributes defined in the annotated
* class will be appended to the configuration attributes defined in
* superclasses.
* @param clazz the class for which to resolve the configuration attributes (must
* not be <code>null</code>)
* @return the list of configuration attributes for the specified class,
* including configuration attributes from superclasses if appropriate
* (never <code>null</code>)
* @throws IllegalArgumentException if the supplied class is <code>null</code>
* or if {@link ContextConfiguration &#064;ContextConfiguration} is not
* <em>present</em> on the supplied class
*/
static List<ContextConfigurationAttributes> resolveContextConfigurationAttributes(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
final List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>();
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
Assert.notNull(declaringClass, String.format(
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType,
clazz));
while (declaringClass != null) {
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].",
contextConfiguration, declaringClass));
}
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(declaringClass,
contextConfiguration);
if (logger.isTraceEnabled()) {
logger.trace("Resolved context configuration attributes: " + attributes);
}
attributesList.add(0, attributes);
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
annotationType, declaringClass.getSuperclass()) : null;
}
return attributesList;
}
/**
* Resolve the {@link ContextLoader} {@link Class class} to use for the
* supplied {@link Class testClass} and {@link ContextConfigurationAttributes}
* and then instantiate and return that {@code ContextLoader}.
* supplied {@link Class testClass} and then instantiate and return that
* {@code ContextLoader}.
* <p>If the supplied <code>defaultContextLoaderClassName</code> is
* <code>null</code> or <em>empty</em>, the <em>standard</em>
* default context loader class name {@value #DEFAULT_CONTEXT_LOADER_CLASS_NAME}
@ -120,25 +67,20 @@ abstract class ContextLoaderUtils { @@ -120,25 +67,20 @@ abstract class ContextLoaderUtils {
* {@link #resolveContextLoaderClass()}.
* @param testClass the test class for which the {@code ContextLoader}
* should be resolved (must not be <code>null</code>)
* @param configAttributesList the resolved configuration attributes for the
* test class hierarchy
* @param defaultContextLoaderClassName the name of the default
* {@code ContextLoader} class to use (may be <code>null</code>)
* @return the resolved {@code ContextLoader} for the supplied
* <code>testClass</code> (never <code>null</code>)
* @see #resolveContextLoaderClass()
* @see #resolveContextConfigurationAttributes()
*/
static ContextLoader resolveContextLoader(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributesList, String defaultContextLoaderClassName) {
static ContextLoader resolveContextLoader(Class<?> testClass, String defaultContextLoaderClassName) {
Assert.notNull(testClass, "Test class must not be null");
Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty");
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
defaultContextLoaderClassName = DEFAULT_CONTEXT_LOADER_CLASS_NAME;
}
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass, configAttributesList,
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
defaultContextLoaderClassName);
return (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass);
@ -146,56 +88,61 @@ abstract class ContextLoaderUtils { @@ -146,56 +88,61 @@ abstract class ContextLoaderUtils {
/**
* Resolve the {@link ContextLoader} {@link Class} to use for the supplied
* {@link ContextConfigurationAttributes} list.
* <p>This method will iterate over the supplied configuration attributes
* and execute the following algorithm:
* {@link Class testClass}.
* <ol>
* <li>If {@link ContextConfigurationAttributes#getContextLoaderClass()}
* returns an explicit implementation class, that class will be returned.</li>
* <li>If an explicit {@code ContextLoader} implementation class is not
* specified, the next {@link ContextConfigurationAttributes} instance in
* the supplied list will be processed; go to step #1.</li>
* <li>If no explicit <code>loader</code> class is found after processing
* all {@link ContextConfigurationAttributes} instances, an attempt will be
* made to load and return the class with the supplied
* <code>defaultContextLoaderClassName</code>.</li>
* <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 @ContextConfiguration}; go to step #1.</li>
* <li>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>.</li>
* </ol>
* @param testClass the class for which to resolve the {@code ContextLoader}
* class; used solely for logging purposes; must not be <code>null</code>
* @param configAttributesList the resolved configuration attributes for the
* test class hierarchy; must not be <code>null</code> or empty
* class; must not be <code>null</code>
* @param defaultContextLoaderClassName the name of the default
* {@code ContextLoader} class to use; must not be <code>null</code> or empty
* @return the {@code ContextLoader} class to use for the specified class
* (never <code>null</code>)
* @return the {@code ContextLoader} class to use for the supplied test class
* @throws IllegalArgumentException if {@code @ContextConfiguration} is not
* <em>present</em> on the supplied test class
* @see #resolveContextLoader()
* @see #resolveContextConfigurationAttributes()
* <em>present</em> on the supplied test class
* @throws IllegalStateException if the default {@code ContextLoader} class
* could not be loaded
*/
@SuppressWarnings("unchecked")
static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributesList, String defaultContextLoaderClassName) {
String defaultContextLoaderClassName) {
Assert.notNull(testClass, "Class must not be null");
Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty");
Assert.hasText(defaultContextLoaderClassName, "Default ContextLoader class name must not be null or empty");
for (ContextConfigurationAttributes configAttributes : configAttributesList) {
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, testClass);
Assert.notNull(declaringClass, String.format(
"Could not find an 'annotation declaring class' for annotation type [%s] and test class [%s]",
annotationType, testClass));
while (declaringClass != null) {
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
if (logger.isTraceEnabled()) {
logger.trace(String.format(
"Processing ContextLoader for context configuration attributes [%s] and test class [%s]",
configAttributes, testClass));
"Processing ContextLoader for @ContextConfiguration [%s] and declaring class [%s]",
contextConfiguration, declaringClass));
}
Class<? extends ContextLoader> contextLoaderClass = configAttributes.getContextLoaderClass();
Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader();
if (!ContextLoader.class.equals(contextLoaderClass)) {
if (logger.isDebugEnabled()) {
logger.debug(String.format(
"Found explicit ContextLoader class [%s] for context configuration attributes [%s] and test class [%s]",
contextLoaderClass, configAttributes, testClass));
"Found explicit ContextLoader class [%s] for @ContextConfiguration [%s] and declaring class [%s]",
contextLoaderClass, contextConfiguration, declaringClass));
}
return contextLoaderClass;
}
declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType,
declaringClass.getSuperclass());
}
try {
@ -213,6 +160,58 @@ abstract class ContextLoaderUtils { @@ -213,6 +160,58 @@ abstract class ContextLoaderUtils {
}
}
/**
* Resolve the list of {@link ContextConfigurationAttributes configuration
* attributes} for the supplied {@link Class class} and its superclasses.
* <p>Note that the {@link ContextConfiguration#inheritLocations
* inheritLocations} flag of {@link ContextConfiguration
* &#064;ContextConfiguration} will be taken into consideration.
* Specifically, if the <code>inheritLocations</code> flag is set to
* <code>true</code>, configuration attributes defined in the annotated
* class will be appended to the configuration attributes defined in
* superclasses.
* @param clazz the class for which to resolve the configuration attributes (must
* not be <code>null</code>)
* @return the list of configuration attributes for the specified class,
* including configuration attributes from superclasses if appropriate
* (never <code>null</code>)
* @throws IllegalArgumentException if the supplied class is <code>null</code> or
* if {@code @ContextConfiguration} is not <em>present</em> on the supplied class
*/
static List<ContextConfigurationAttributes> resolveContextConfigurationAttributes(Class<?> clazz) {
Assert.notNull(clazz, "Class must not be null");
final List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>();
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
Assert.notNull(declaringClass, String.format(
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType,
clazz));
while (declaringClass != null) {
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].",
contextConfiguration, declaringClass));
}
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(declaringClass,
contextConfiguration);
if (logger.isTraceEnabled()) {
logger.trace("Resolved context configuration attributes: " + attributes);
}
attributesList.add(0, attributes);
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
annotationType, declaringClass.getSuperclass()) : null;
}
return attributesList;
}
/**
* Resolve <em>active bean definition profiles</em> for the supplied {@link Class}.
* <p>Note that the {@link ActiveProfiles#inheritProfiles inheritProfiles}
@ -286,8 +285,8 @@ abstract class ContextLoaderUtils { @@ -286,8 +285,8 @@ abstract class ContextLoaderUtils {
* @param defaultContextLoaderClassName the name of the default
* {@code ContextLoader} class to use (may be <code>null</code>)
* @return the merged context configuration
* @see #resolveContextConfigurationAttributes()
* @see #resolveContextLoader()
* @see #resolveContextConfigurationAttributes()
* @see SmartContextLoader#processContextConfiguration()
* @see ContextLoader#processLocations()
* @see #resolveActiveProfiles()
@ -296,16 +295,8 @@ abstract class ContextLoaderUtils { @@ -296,16 +295,8 @@ abstract class ContextLoaderUtils {
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass,
String defaultContextLoaderClassName) {
List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass);
ContextLoader contextLoader = resolveContextLoader(testClass, configAttributesList,
defaultContextLoaderClassName);
// Algorithm:
// - iterate over config attributes
// -- let loader process locations
// -- let loader process classes, if it's a SmartContextLoader
final ContextLoader contextLoader = resolveContextLoader(testClass, defaultContextLoaderClassName);
final List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass);
final List<String> locationsList = new ArrayList<String>();
final List<Class<?>> classesList = new ArrayList<Class<?>>();

Loading…
Cancel
Save