Browse Source

[SPR-6184] Implemented recursive search for configuration classes; introduced LocationsResolver strategy in ContextLoaderUtils with ResourcePathLocationsResolver and ClassNameLocationsResolver implementations.

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4168 50f2f4bb-b051-0410-bef5-90022cba6387
pull/1/merge
Sam Brannen 15 years ago
parent
commit
190da51082
  1. 98
      org.springframework.test/src/main/java/org/springframework/test/context/ContextLoaderUtils.java
  2. 4
      org.springframework.test/src/test/java/org/springframework/test/context/junit4/SpringJUnit4SuiteTests.java
  3. 2
      org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java
  4. 12
      org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/AnnotationConfigSuiteTests.java
  5. 2
      org.springframework.test/src/test/java/org/springframework/test/context/junit4/annotation/DefaultConfigClassInheritedTests.java

98
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}. * Utility methods for working with {@link ContextLoader ContextLoaders}.
* *
* <p>TODO: Consider refactoring into a stateful ContextLoaderResolver. * <p>TODO Consider refactoring into a stateful ContextLoaderResolver.
* *
* @author Sam Brannen * @author Sam Brannen
* @since 3.1 * @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 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(). * TODO Document resolveContextLoader().
@ -164,91 +167,82 @@ public abstract class ContextLoaderUtils {
Class<ContextConfiguration> annotationType = ContextConfiguration.class; Class<ContextConfiguration> annotationType = ContextConfiguration.class;
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz); Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
Assert.notNull(declaringClass, "Could not find an 'annotation declaring class' for annotation type [" Assert.notNull(declaringClass, String.format(
+ annotationType + "] and class [" + clazz + "]"); "Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType,
clazz));
boolean processConfigurationClasses = (contextLoader instanceof ResourceTypeAwareContextLoader) boolean processConfigurationClasses = (contextLoader instanceof ResourceTypeAwareContextLoader)
&& ((ResourceTypeAwareContextLoader) contextLoader).supportsClassResources(); && ((ResourceTypeAwareContextLoader) contextLoader).supportsClassResources();
LocationsResolver locationsResolver = processConfigurationClasses ? classNameLocationsResolver
return processConfigurationClasses ? // : resourcePathLocationsResolver;
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<ContextConfiguration> annotationType, Class<?> declaringClass) {
List<String> locationsList = new ArrayList<String>(); List<String> locationsList = new ArrayList<String>();
while (declaringClass != null) { while (declaringClass != null) {
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType); ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].", logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].",
contextConfiguration, declaringClass)); contextConfiguration, declaringClass));
} }
String[] valueLocations = contextConfiguration.value(); String[] resolvedLocations = locationsResolver.resolveLocations(contextConfiguration, declaringClass);
String[] processedLocations = contextLoader.processLocations(declaringClass, resolvedLocations);
locationsList.addAll(0, Arrays.<String> asList(processedLocations));
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
annotationType, declaringClass.getSuperclass()) : null;
}
return locationsList.toArray(new String[locationsList.size()]);
}
private static interface LocationsResolver {
String[] resolveLocations(ContextConfiguration contextConfiguration, Class<?> declaringClass);
}
private static final class ResourcePathLocationsResolver implements LocationsResolver {
public String[] resolveLocations(ContextConfiguration contextConfiguration, Class<?> declaringClass) {
String[] locations = contextConfiguration.locations(); String[] locations = contextConfiguration.locations();
String[] valueLocations = contextConfiguration.value();
if (!ObjectUtils.isEmpty(valueLocations) && !ObjectUtils.isEmpty(locations)) { if (!ObjectUtils.isEmpty(valueLocations) && !ObjectUtils.isEmpty(locations)) {
String msg = String.format( 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.", "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), declaringClass, ObjectUtils.nullSafeToString(valueLocations),
ObjectUtils.nullSafeToString(locations)); ObjectUtils.nullSafeToString(locations));
logger.error(msg); ContextLoaderUtils.logger.error(msg);
throw new IllegalStateException(msg); throw new IllegalStateException(msg);
} }
else if (!ObjectUtils.isEmpty(valueLocations)) { else if (!ObjectUtils.isEmpty(valueLocations)) {
locations = valueLocations; locations = valueLocations;
} }
locations = contextLoader.processLocations(declaringClass, locations); return locations;
locationsList.addAll(0, Arrays.<String> asList(locations));
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
annotationType, declaringClass.getSuperclass()) : null;
} }
return locationsList.toArray(new String[locationsList.size()]);
} }
/** private static final class ClassNameLocationsResolver implements LocationsResolver {
* TODO Document resolveConfigClassNames().
*
* @param contextLoader
* @param annotationType
* @param declaringClass
* @return
*/
private static String[] resolveConfigurationClassNames(ContextLoader contextLoader,
Class<ContextConfiguration> annotationType, Class<?> declaringClass) {
// TODO [SPR-6184] Implement recursive search for configuration classes. public String[] resolveLocations(ContextConfiguration contextConfiguration, Class<?> declaringClass) {
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType); String[] classNames = null;
if (logger.isTraceEnabled()) {
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].",
contextConfiguration, declaringClass));
}
String[] classNames = null; Class<?>[] configClasses = contextConfiguration.classes();
if (!ObjectUtils.isEmpty(configClasses)) {
classNames = new String[configClasses.length];
Class<?>[] configClasses = contextConfiguration.classes(); for (int i = 0; i < configClasses.length; i++) {
if (!ObjectUtils.isEmpty(configClasses)) { classNames[i] = configClasses[i].getName();
classNames = new String[configClasses.length]; }
for (int i = 0; i < configClasses.length; i++) {
classNames[i] = configClasses[i].getName();
} }
}
return contextLoader.processLocations(declaringClass, classNames); return classNames;
}
} }
} }

4
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.ClassLevelDirtiesContextTests;
import org.springframework.test.context.SpringRunnerContextCacheTests; import org.springframework.test.context.SpringRunnerContextCacheTests;
import org.springframework.test.context.junit4.annotation.AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests; 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; import org.springframework.test.context.junit4.orm.HibernateSessionFlushingTests;
/** /**
@ -50,6 +52,8 @@ StandardJUnit4FeaturesTests.class,//
StandardJUnit4FeaturesSpringRunnerTests.class,// StandardJUnit4FeaturesSpringRunnerTests.class,//
SpringJUnit47ClassRunnerRuleTests.class,// SpringJUnit47ClassRunnerRuleTests.class,//
AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,// AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,//
DefaultConfigClassBaseTests.class,//
DefaultConfigClassInheritedTests.class,//
ExpectedExceptionSpringRunnerTests.class,// ExpectedExceptionSpringRunnerTests.class,//
TimedSpringRunnerTests.class,// TimedSpringRunnerTests.class,//
RepeatedSpringRunnerTests.class,// RepeatedSpringRunnerTests.class,//

2
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 * @author Sam Brannen
* @since 3.1 * @since 3.1
*/ */
@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = PojoAndStringConfig.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = PojoAndStringConfig.class, inheritLocations = false)
public class AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { public class AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests {
/* all tests are in the parent class. */ /* all tests are in the parent class. */
} }

12
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) @RunWith(Suite.class)
// Note: the following 'multi-line' layout is for enhanced code readability. // Note: the following 'multi-line' layout is for enhanced code readability.
@SuiteClasses({ @SuiteClasses({//
AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,//
AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class, DefaultConfigClassBaseTests.class,//
DefaultConfigClassInheritedTests.class //
DefaultConfigClassBaseTests.class,
DefaultConfigClassInheritedTests.class
}) })
public class AnnotationConfigSuiteTests { public class AnnotationConfigSuiteTests {
} }

2
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.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.Pet; import org.springframework.beans.Pet;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -31,7 +30,6 @@ import org.springframework.test.context.ContextConfiguration;
* @author Sam Brannen * @author Sam Brannen
* @since 3.1 * @since 3.1
*/ */
@Ignore("[SPR-6184] Disabled until ContextLoaderUtils supports recursive search for configuration classes")
@ContextConfiguration @ContextConfiguration
public class DefaultConfigClassInheritedTests extends DefaultConfigClassBaseTests { public class DefaultConfigClassInheritedTests extends DefaultConfigClassBaseTests {

Loading…
Cancel
Save