From 2b5d2e5a0ac385c61276c56e86a9e513f47d39cf Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 20 Jun 2011 21:49:44 +0000 Subject: [PATCH] [SPR-8386] ContextLoader resolution once again ignores the inheritLocations flag on @ContextConfiguration. --- .../test/context/ContextLoaderUtils.java | 193 +++++++++--------- 1 file changed, 92 insertions(+), 101 deletions(-) diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java b/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java index 295ce15d9f..37046eb931 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java @@ -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. - *

Note that the {@link ContextConfiguration#inheritLocations - * inheritLocations} flag of {@link ContextConfiguration - * @ContextConfiguration} will be taken into consideration. - * Specifically, if the inheritLocations flag is set to - * true, 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 null) - * @return the list of configuration attributes for the specified class, - * including configuration attributes from superclasses if appropriate - * (never null) - * @throws IllegalArgumentException if the supplied class is null - * or if {@link ContextConfiguration @ContextConfiguration} is not - * present on the supplied class - */ - static List resolveContextConfigurationAttributes(Class clazz) { - Assert.notNull(clazz, "Class must not be null"); - - final List attributesList = new ArrayList(); - - Class 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}. *

If the supplied defaultContextLoaderClassName is * null or empty, the standard * default context loader class name {@value #DEFAULT_CONTEXT_LOADER_CLASS_NAME} @@ -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 null) - * @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 null) * @return the resolved {@code ContextLoader} for the supplied * testClass (never null) * @see #resolveContextLoaderClass() - * @see #resolveContextConfigurationAttributes() */ - static ContextLoader resolveContextLoader(Class testClass, - List 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 contextLoaderClass = resolveContextLoaderClass(testClass, configAttributesList, + Class contextLoaderClass = resolveContextLoaderClass(testClass, defaultContextLoaderClassName); return (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass); @@ -146,56 +88,61 @@ abstract class ContextLoaderUtils { /** * Resolve the {@link ContextLoader} {@link Class} to use for the supplied - * {@link ContextConfigurationAttributes} list. - *

This method will iterate over the supplied configuration attributes - * and execute the following algorithm: + * {@link Class testClass}. *

    - *
  1. If {@link ContextConfigurationAttributes#getContextLoaderClass()} - * returns an explicit implementation class, that class will be returned.
  2. - *
  3. 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.
  4. - *
  5. If no explicit loader class is found after processing - * all {@link ContextConfigurationAttributes} instances, an attempt will be - * made to load and return the class with the supplied - * defaultContextLoaderClassName.
  6. + *
  7. If the {@link ContextConfiguration#loader() loader} attribute of + * {@link ContextConfiguration @ContextConfiguration} is configured + * with an explicit class, that class will be returned.
  8. + *
  9. If a loader class is not specified, the class hierarchy + * will be traversed to find a parent class annotated with + * {@code @ContextConfiguration}; go to step #1.
  10. + *
  11. If no explicit loader class is found after traversing + * the class hierarchy, an attempt will be made to load and return the class + * with the supplied defaultContextLoaderClassName.
  12. *
* @param testClass the class for which to resolve the {@code ContextLoader} - * class; used solely for logging purposes; must not be null - * @param configAttributesList the resolved configuration attributes for the - * test class hierarchy; must not be null or empty + * class; must not be null * @param defaultContextLoaderClassName the name of the default * {@code ContextLoader} class to use; must not be null or empty - * @return the {@code ContextLoader} class to use for the specified class - * (never null) + * @return the {@code ContextLoader} class to use for the supplied test class * @throws IllegalArgumentException if {@code @ContextConfiguration} is not - * present on the supplied test class - * @see #resolveContextLoader() - * @see #resolveContextConfigurationAttributes() + * present on the supplied test class + * @throws IllegalStateException if the default {@code ContextLoader} class + * could not be loaded */ @SuppressWarnings("unchecked") static Class resolveContextLoaderClass(Class testClass, - List 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 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 contextLoaderClass = configAttributes.getContextLoaderClass(); + Class 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 { } } + /** + * Resolve the list of {@link ContextConfigurationAttributes configuration + * attributes} for the supplied {@link Class class} and its superclasses. + *

Note that the {@link ContextConfiguration#inheritLocations + * inheritLocations} flag of {@link ContextConfiguration + * @ContextConfiguration} will be taken into consideration. + * Specifically, if the inheritLocations flag is set to + * true, 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 null) + * @return the list of configuration attributes for the specified class, + * including configuration attributes from superclasses if appropriate + * (never null) + * @throws IllegalArgumentException if the supplied class is null or + * if {@code @ContextConfiguration} is not present on the supplied class + */ + static List resolveContextConfigurationAttributes(Class clazz) { + Assert.notNull(clazz, "Class must not be null"); + + final List attributesList = new ArrayList(); + + Class 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 active bean definition profiles for the supplied {@link Class}. *

Note that the {@link ActiveProfiles#inheritProfiles inheritProfiles} @@ -286,8 +285,8 @@ abstract class ContextLoaderUtils { * @param defaultContextLoaderClassName the name of the default * {@code ContextLoader} class to use (may be null) * @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 { static MergedContextConfiguration buildMergedContextConfiguration(Class testClass, String defaultContextLoaderClassName) { - List 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 configAttributesList = resolveContextConfigurationAttributes(testClass); final List locationsList = new ArrayList(); final List> classesList = new ArrayList>();