From 4dcc79d6eb8ccf6d5e84abda68f99abe3b641f6f Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sun, 3 Apr 2011 23:10:28 +0000 Subject: [PATCH] [SPR-6184] Implemented recursive search for configuration classes; introduced LocationsResolver strategy in ContextLoaderUtils with ResourcePathLocationsResolver and ClassNameLocationsResolver implementations. --- .../test/context/ContextLoaderUtils.java | 110 +++++++++--------- .../junit4/SpringJUnit4SuiteTests.java | 4 + ...figSpringJUnit4ClassRunnerAppCtxTests.java | 2 +- .../AnnotationConfigSuiteTests.java | 12 +- .../DefaultConfigClassInheritedTests.java | 2 - 5 files changed, 61 insertions(+), 69 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 51dfbaac63a..83a1d365e1a 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 @@ -32,7 +32,7 @@ import org.springframework.util.StringUtils; /** * Utility methods for working with {@link ContextLoader ContextLoaders}. * - *

TODO: Consider refactoring into a stateful ContextLoaderResolver. + *

TODO Consider refactoring into a stateful ContextLoaderResolver. * * @author Sam Brannen * @since 3.1 @@ -44,6 +44,9 @@ public abstract class ContextLoaderUtils { private static final String STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.GenericXmlContextLoader"; + private static final ClassNameLocationsResolver classNameLocationsResolver = new ClassNameLocationsResolver(); + private static final ResourcePathLocationsResolver resourcePathLocationsResolver = new ResourcePathLocationsResolver(); + /** * TODO Document resolveContextLoader(). @@ -164,53 +167,29 @@ public abstract class ContextLoaderUtils { Class 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 + "]"); + Assert.notNull(declaringClass, String.format( + "Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType, + clazz)); boolean processConfigurationClasses = (contextLoader instanceof ResourceTypeAwareContextLoader) && ((ResourceTypeAwareContextLoader) contextLoader).supportsClassResources(); - - return processConfigurationClasses ? // - resolveConfigurationClassNames(contextLoader, annotationType, declaringClass) - : resolveStringLocations(contextLoader, annotationType, declaringClass); - } - - /** - * TODO Document resolveStringLocations(). - * - * @param contextLoader - * @param annotationType - * @param declaringClass - * @return - */ - private static String[] resolveStringLocations(ContextLoader contextLoader, - Class annotationType, Class declaringClass) { + LocationsResolver locationsResolver = processConfigurationClasses ? classNameLocationsResolver + : resourcePathLocationsResolver; List locationsList = new ArrayList(); while (declaringClass != null) { ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType); + if (logger.isTraceEnabled()) { logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].", contextConfiguration, declaringClass)); } - String[] valueLocations = contextConfiguration.value(); - String[] locations = contextConfiguration.locations(); - if (!ObjectUtils.isEmpty(valueLocations) && !ObjectUtils.isEmpty(locations)) { - String msg = String.format( - "Test class [%s] has been configured with @ContextConfiguration's 'value' [%s] and 'locations' [%s] attributes. Only one declaration of resource locations is permitted per @ContextConfiguration annotation.", - declaringClass, ObjectUtils.nullSafeToString(valueLocations), - ObjectUtils.nullSafeToString(locations)); - logger.error(msg); - throw new IllegalStateException(msg); - } - else if (!ObjectUtils.isEmpty(valueLocations)) { - locations = valueLocations; - } + String[] resolvedLocations = locationsResolver.resolveLocations(contextConfiguration, declaringClass); + String[] processedLocations = contextLoader.processLocations(declaringClass, resolvedLocations); + locationsList.addAll(0, Arrays. asList(processedLocations)); - locations = contextLoader.processLocations(declaringClass, locations); - locationsList.addAll(0, Arrays. asList(locations)); declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass( annotationType, declaringClass.getSuperclass()) : null; } @@ -218,37 +197,52 @@ public abstract class ContextLoaderUtils { return locationsList.toArray(new String[locationsList.size()]); } - /** - * TODO Document resolveConfigClassNames(). - * - * @param contextLoader - * @param annotationType - * @param declaringClass - * @return - */ - private static String[] resolveConfigurationClassNames(ContextLoader contextLoader, - Class annotationType, Class declaringClass) { - // TODO [SPR-6184] Implement recursive search for configuration classes. + private static interface LocationsResolver { - ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType); - if (logger.isTraceEnabled()) { - logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].", - contextConfiguration, declaringClass)); - } + String[] resolveLocations(ContextConfiguration contextConfiguration, Class declaringClass); + } - String[] classNames = null; + private static final class ResourcePathLocationsResolver implements LocationsResolver { - Class[] configClasses = contextConfiguration.classes(); - if (!ObjectUtils.isEmpty(configClasses)) { - classNames = new String[configClasses.length]; + public String[] resolveLocations(ContextConfiguration contextConfiguration, Class declaringClass) { - for (int i = 0; i < configClasses.length; i++) { - classNames[i] = configClasses[i].getName(); + String[] locations = contextConfiguration.locations(); + String[] valueLocations = contextConfiguration.value(); + + if (!ObjectUtils.isEmpty(valueLocations) && !ObjectUtils.isEmpty(locations)) { + String msg = String.format( + "Test class [%s] has been configured with @ContextConfiguration's 'value' [%s] and 'locations' [%s] attributes. Only one declaration of resource locations is permitted per @ContextConfiguration annotation.", + declaringClass, ObjectUtils.nullSafeToString(valueLocations), + ObjectUtils.nullSafeToString(locations)); + ContextLoaderUtils.logger.error(msg); + throw new IllegalStateException(msg); + } + else if (!ObjectUtils.isEmpty(valueLocations)) { + locations = valueLocations; } - } - return contextLoader.processLocations(declaringClass, classNames); + return locations; + } + } + + private static final class ClassNameLocationsResolver implements LocationsResolver { + + public String[] resolveLocations(ContextConfiguration contextConfiguration, Class declaringClass) { + + String[] classNames = null; + + Class[] configClasses = contextConfiguration.classes(); + if (!ObjectUtils.isEmpty(configClasses)) { + classNames = new String[configClasses.length]; + + for (int i = 0; i < configClasses.length; i++) { + classNames[i] = configClasses[i].getName(); + } + } + + return classNames; + } } } diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java index 069eb427174..58bff255cd3 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java @@ -22,6 +22,8 @@ import org.junit.runners.Suite.SuiteClasses; import org.springframework.test.context.ClassLevelDirtiesContextTests; import org.springframework.test.context.SpringRunnerContextCacheTests; import org.springframework.test.context.junit4.annotation.AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests; +import org.springframework.test.context.junit4.annotation.DefaultConfigClassBaseTests; +import org.springframework.test.context.junit4.annotation.DefaultConfigClassInheritedTests; import org.springframework.test.context.junit4.orm.HibernateSessionFlushingTests; /** @@ -50,6 +52,8 @@ StandardJUnit4FeaturesTests.class,// StandardJUnit4FeaturesSpringRunnerTests.class,// SpringJUnit47ClassRunnerRuleTests.class,// AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,// + DefaultConfigClassBaseTests.class,// + DefaultConfigClassInheritedTests.class,// ExpectedExceptionSpringRunnerTests.class,// TimedSpringRunnerTests.class,// RepeatedSpringRunnerTests.class,// diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java index 91df99f1393..4b2b7eb0673 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java @@ -26,7 +26,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader; * @author Sam Brannen * @since 3.1 */ -@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = PojoAndStringConfig.class) +@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = PojoAndStringConfig.class, inheritLocations = false) public class AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { /* all tests are in the parent class. */ } diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSuiteTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSuiteTests.java index 740c7888e11..7c5445634b6 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSuiteTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSuiteTests.java @@ -28,14 +28,10 @@ import org.junit.runners.Suite.SuiteClasses; */ @RunWith(Suite.class) // Note: the following 'multi-line' layout is for enhanced code readability. -@SuiteClasses({ - -AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class, - -DefaultConfigClassBaseTests.class, - -DefaultConfigClassInheritedTests.class - +@SuiteClasses({// +AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,// + DefaultConfigClassBaseTests.class,// + DefaultConfigClassInheritedTests.class // }) public class AnnotationConfigSuiteTests { } diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/DefaultConfigClassInheritedTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/DefaultConfigClassInheritedTests.java index caf769b49b9..0c0011a5bfd 100644 --- a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/DefaultConfigClassInheritedTests.java +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/DefaultConfigClassInheritedTests.java @@ -19,7 +19,6 @@ package org.springframework.test.context.junit4.annotation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.Pet; import org.springframework.beans.factory.annotation.Autowired; @@ -31,7 +30,6 @@ import org.springframework.test.context.ContextConfiguration; * @author Sam Brannen * @since 3.1 */ -@Ignore("[SPR-6184] Disabled until ContextLoaderUtils supports recursive search for configuration classes") @ContextConfiguration public class DefaultConfigClassInheritedTests extends DefaultConfigClassBaseTests {