[SPR-8386] SmartContextLoader enhancements:
- introduced processContextConfigurationAttributes() method in SmartContextLoader SPI - refactored AnnotationConfigContextLoader, AbstractContextLoader, AbstractGenericContextLoader, ContextLoaderUtils, and TestContext implementations to take advantage of the SmartContextLoader SPI, MergedContextConfiguration, and ContextConfigurationAttributes - deleted ResourceTypeAwareContextLoader - deleted ContextLoaderUtils.LocationsResolver and implementations - moved context key generation from TestContext to MergedContextConfiguration
This commit is contained in:
parent
8e35734856
commit
9a56deb283
|
|
@ -34,13 +34,13 @@ public class ContextConfigurationAttributes {
|
|||
|
||||
private final Class<?> declaringClass;
|
||||
|
||||
private final String[] locations;
|
||||
private String[] locations;
|
||||
|
||||
private final Class<?>[] classes;
|
||||
private Class<?>[] classes;
|
||||
|
||||
private final boolean inheritLocations;
|
||||
|
||||
private final Class<? extends ContextLoader> contextLoader;
|
||||
private final Class<? extends ContextLoader> contextLoaderClass;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -72,9 +72,6 @@ public class ContextConfigurationAttributes {
|
|||
|
||||
/**
|
||||
* TODO Document ContextConfigurationAttributes constructor.
|
||||
*
|
||||
* @param declaringClass
|
||||
* @param contextConfiguration
|
||||
*/
|
||||
public ContextConfigurationAttributes(Class<?> declaringClass, ContextConfiguration contextConfiguration) {
|
||||
this(declaringClass, resolveLocations(declaringClass, contextConfiguration), contextConfiguration.classes(),
|
||||
|
|
@ -83,20 +80,14 @@ public class ContextConfigurationAttributes {
|
|||
|
||||
/**
|
||||
* TODO Document ContextConfigurationAttributes constructor.
|
||||
*
|
||||
* @param declaringClass
|
||||
* @param locations
|
||||
* @param classes
|
||||
* @param inheritLocations
|
||||
* @param contextLoader
|
||||
*/
|
||||
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
|
||||
boolean inheritLocations, Class<? extends ContextLoader> contextLoader) {
|
||||
boolean inheritLocations, Class<? extends ContextLoader> contextLoaderClass) {
|
||||
this.declaringClass = declaringClass;
|
||||
this.locations = locations;
|
||||
this.classes = classes;
|
||||
this.inheritLocations = inheritLocations;
|
||||
this.contextLoader = contextLoader;
|
||||
this.contextLoaderClass = contextLoaderClass;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -113,6 +104,13 @@ public class ContextConfigurationAttributes {
|
|||
return this.locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document setLocations().
|
||||
*/
|
||||
public void setLocations(String[] locations) {
|
||||
this.locations = locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getClasses().
|
||||
*/
|
||||
|
|
@ -120,6 +118,13 @@ public class ContextConfigurationAttributes {
|
|||
return this.classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document setClasses().
|
||||
*/
|
||||
public void setClasses(Class<?>[] classes) {
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document isInheritLocations().
|
||||
*/
|
||||
|
|
@ -128,10 +133,10 @@ public class ContextConfigurationAttributes {
|
|||
}
|
||||
|
||||
/**
|
||||
* TODO Document getContextLoader().
|
||||
* TODO Document getContextLoaderClass().
|
||||
*/
|
||||
public Class<? extends ContextLoader> getContextLoader() {
|
||||
return this.contextLoader;
|
||||
public Class<? extends ContextLoader> getContextLoaderClass() {
|
||||
return this.contextLoaderClass;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,7 +149,7 @@ public class ContextConfigurationAttributes {
|
|||
.append("locations", ObjectUtils.nullSafeToString(this.locations))//
|
||||
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
||||
.append("inheritLocations", this.inheritLocations)//
|
||||
.append("contextLoader", this.contextLoader)//
|
||||
.append("contextLoaderClass", this.contextLoaderClass)//
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,10 +25,9 @@ import java.util.Set;
|
|||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.test.context.ResourceTypeAwareContextLoader.ResourceType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
|
|
@ -40,21 +39,53 @@ import org.springframework.util.StringUtils;
|
|||
* @since 3.1
|
||||
* @see ContextLoader
|
||||
* @see ContextConfiguration
|
||||
* @see ContextConfigurationAttributes
|
||||
* @see ActiveProfiles
|
||||
* @see MergedContextConfiguration
|
||||
*/
|
||||
abstract class ContextLoaderUtils {
|
||||
|
||||
// TODO Consider refactoring ContextLoaderUtils into a stateful
|
||||
// ContextLoaderResolver.
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ContextLoaderUtils.class);
|
||||
|
||||
private static final String STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME = "org.springframework.test.context.support.GenericXmlContextLoader";
|
||||
|
||||
private static final ResourcePathLocationsResolver resourcePathLocationsResolver = new ResourcePathLocationsResolver();
|
||||
private static final ClassNameLocationsResolver classNameLocationsResolver = new ClassNameLocationsResolver();
|
||||
|
||||
/**
|
||||
* TODO Document resolveContextConfigurationAttributes().
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the {@link ContextLoader} {@link Class} to use for the
|
||||
|
|
@ -66,22 +97,27 @@ abstract class ContextLoaderUtils {
|
|||
* default context loader class name ({@value #STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME})
|
||||
* will be used. For details on the class resolution process, see
|
||||
* {@link #resolveContextLoaderClass(Class, String)}.
|
||||
*
|
||||
* @param testClass the test class for which the <code>ContextLoader</code>
|
||||
* should be resolved (must not be <code>null</code>)
|
||||
* @param configAttributesList TODO Document parameter
|
||||
* @param defaultContextLoaderClassName the name of the default
|
||||
* <code>ContextLoader</code> class to use (may be <code>null</code>)
|
||||
*
|
||||
* @return the resolved <code>ContextLoader</code> for the supplied
|
||||
* <code>testClass</code> (never <code>null</code>)
|
||||
* @see #resolveContextLoaderClass(Class, String)
|
||||
*/
|
||||
static ContextLoader resolveContextLoader(Class<?> testClass, String defaultContextLoaderClassName) {
|
||||
static ContextLoader resolveContextLoader(Class<?> testClass,
|
||||
List<ContextConfigurationAttributes> configAttributesList, 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 = STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
||||
}
|
||||
|
||||
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
|
||||
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass, configAttributesList,
|
||||
defaultContextLoaderClassName);
|
||||
|
||||
return (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass);
|
||||
|
|
@ -103,52 +139,46 @@ abstract class ContextLoaderUtils {
|
|||
* with the supplied <code>defaultContextLoaderClassName</code>.</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param clazz the class for which to resolve the <code>ContextLoader</code>
|
||||
* @param testClass the class for which to resolve the <code>ContextLoader</code>
|
||||
* class; must not be <code>null</code>
|
||||
* @param configAttributesList TODO Document parameter
|
||||
* @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
|
||||
* (never <code>null</code>)
|
||||
* @throws IllegalArgumentException if {@link ContextConfiguration
|
||||
* @ContextConfiguration} is not <em>present</em> on the supplied class
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> clazz, String defaultContextLoaderClassName) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> testClass,
|
||||
List<ContextConfigurationAttributes> configAttributesList, 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");
|
||||
|
||||
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);
|
||||
for (ContextConfigurationAttributes configAttributes : configAttributesList) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Processing ContextLoader for @ContextConfiguration [" + contextConfiguration
|
||||
+ "] and declaring class [" + declaringClass + "]");
|
||||
logger.trace(String.format(
|
||||
"Processing ContextLoader for context configuration attributes [%s] and test class [%s]",
|
||||
configAttributes, testClass));
|
||||
}
|
||||
|
||||
Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader();
|
||||
Class<? extends ContextLoader> contextLoaderClass = configAttributes.getContextLoaderClass();
|
||||
if (!ContextLoader.class.equals(contextLoaderClass)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found explicit ContextLoader [" + contextLoaderClass
|
||||
+ "] for @ContextConfiguration [" + contextConfiguration + "] and declaring class ["
|
||||
+ declaringClass + "]");
|
||||
logger.debug(String.format(
|
||||
"Found explicit ContextLoader class [%s] for context configuration attributes [%s] and test class [%s]",
|
||||
contextLoaderClass, configAttributes, testClass));
|
||||
}
|
||||
return contextLoaderClass;
|
||||
}
|
||||
|
||||
declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType,
|
||||
declaringClass.getSuperclass());
|
||||
}
|
||||
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
ContextConfiguration contextConfiguration = clazz.getAnnotation(annotationType);
|
||||
logger.trace("Using default ContextLoader class [" + defaultContextLoaderClassName
|
||||
+ "] for @ContextConfiguration [" + contextConfiguration + "] and class [" + clazz + "]");
|
||||
logger.trace(String.format("Using default ContextLoader class [%s] for test class [%s]",
|
||||
defaultContextLoaderClassName, testClass));
|
||||
}
|
||||
return (Class<? extends ContextLoader>) ContextLoaderUtils.class.getClassLoader().loadClass(
|
||||
defaultContextLoaderClassName);
|
||||
|
|
@ -160,65 +190,6 @@ abstract class ContextLoaderUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves {@link ApplicationContext} resource locations for the supplied
|
||||
* {@link Class class}, using the supplied {@link ContextLoader} to
|
||||
* {@link ContextLoader#processLocations(Class, String...) process} the
|
||||
* locations.
|
||||
*
|
||||
* <p>Note that the {@link ContextConfiguration#inheritLocations()
|
||||
* inheritLocations} flag of {@link ContextConfiguration
|
||||
* @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.
|
||||
*
|
||||
* @param contextLoader the ContextLoader to use for processing the
|
||||
* locations (must not be <code>null</code>)
|
||||
* @param clazz the class for which to resolve the resource locations (must
|
||||
* not be <code>null</code>)
|
||||
* @return the list of ApplicationContext resource locations for the
|
||||
* specified class, including locations from superclasses if appropriate
|
||||
* (never <code>null</code>)
|
||||
* @throws IllegalArgumentException if {@link ContextConfiguration
|
||||
* @ContextConfiguration} is not <em>present</em> on the supplied class
|
||||
*/
|
||||
static String[] resolveContextLocations(ContextLoader contextLoader, Class<?> clazz) {
|
||||
Assert.notNull(contextLoader, "ContextLoader must not be null");
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
|
||||
boolean processConfigurationClasses = (contextLoader instanceof ResourceTypeAwareContextLoader)
|
||||
&& ResourceType.CLASSES == ((ResourceTypeAwareContextLoader) contextLoader).getResourceType();
|
||||
LocationsResolver locationsResolver = processConfigurationClasses ? classNameLocationsResolver
|
||||
: resourcePathLocationsResolver;
|
||||
|
||||
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));
|
||||
|
||||
final List<String> locationsList = new ArrayList<String>();
|
||||
|
||||
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[] resolvedLocations = locationsResolver.resolveLocations(contextConfiguration, declaringClass);
|
||||
String[] processedLocations = contextLoader.processLocations(declaringClass, resolvedLocations);
|
||||
locationsList.addAll(0, Arrays.asList(processedLocations));
|
||||
|
||||
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
|
||||
annotationType, declaringClass.getSuperclass()) : null;
|
||||
}
|
||||
|
||||
return StringUtils.toStringArray(locationsList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves <em>active bean definition profiles</em> for the supplied
|
||||
* {@link Class class}.
|
||||
|
|
@ -231,6 +202,7 @@ abstract class ContextLoaderUtils {
|
|||
*
|
||||
* @param clazz the class for which to resolve the active profiles (must
|
||||
* not be <code>null</code>)
|
||||
*
|
||||
* @return the set of active profiles for the specified class, including
|
||||
* active profiles from superclasses if appropriate (never <code>null</code>)
|
||||
*/
|
||||
|
|
@ -284,136 +256,77 @@ abstract class ContextLoaderUtils {
|
|||
return StringUtils.toStringArray(activeProfiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document resolveContextConfigurationAttributes().
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
/*
|
||||
* Resolves {@link ApplicationContext} resource locations for the supplied
|
||||
* {@link Class class}, using the supplied {@link ContextLoader} to {@link
|
||||
* ContextLoader#processLocations(Class, String...) process} the locations.
|
||||
*
|
||||
* <p>Note that the {@link ContextConfiguration#inheritLocations()
|
||||
* inheritLocations} flag of {@link ContextConfiguration
|
||||
* @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.
|
||||
*
|
||||
* @param contextLoader the ContextLoader to use for processing the
|
||||
* locations (must not be <code>null</code>)
|
||||
*
|
||||
* @param clazz the class for which to resolve the resource locations (must
|
||||
* not be <code>null</code>)
|
||||
*
|
||||
* @return the list of ApplicationContext resource locations for the
|
||||
* specified class, including locations from superclasses if appropriate
|
||||
* (never <code>null</code>)
|
||||
*
|
||||
* @throws IllegalArgumentException if {@link ContextConfiguration
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document buildMergedContextConfiguration().
|
||||
*
|
||||
* @param testClass
|
||||
* @param defaultContextLoaderClassName
|
||||
* @return
|
||||
*/
|
||||
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass,
|
||||
String defaultContextLoaderClassName) {
|
||||
|
||||
ContextLoader contextLoader = resolveContextLoader(testClass, defaultContextLoaderClassName);
|
||||
List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass);
|
||||
|
||||
// TODO Merge locations from List<ContextConfigurationAttributes>
|
||||
String[] locations = resolveContextLocations(contextLoader, testClass);
|
||||
ContextLoader contextLoader = resolveContextLoader(testClass, configAttributesList,
|
||||
defaultContextLoaderClassName);
|
||||
|
||||
// TODO Merge classes from List<ContextConfigurationAttributes>
|
||||
Class<?>[] classes = {};
|
||||
// Algorithm:
|
||||
// - iterate over config attributes
|
||||
// -- let loader process locations
|
||||
// -- let loader process classes, if it's a SmartContextLoader
|
||||
|
||||
final List<String> locationsList = new ArrayList<String>();
|
||||
final List<Class<?>> classesList = new ArrayList<Class<?>>();
|
||||
|
||||
for (ContextConfigurationAttributes configAttributes : configAttributesList) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(String.format(
|
||||
"Processing locations and classes for context configuration attributes [%s]", configAttributes));
|
||||
}
|
||||
|
||||
if (contextLoader instanceof SmartContextLoader) {
|
||||
SmartContextLoader smartContextLoader = (SmartContextLoader) contextLoader;
|
||||
// TODO Decide on mutability of locations and classes properties
|
||||
smartContextLoader.processContextConfigurationAttributes(configAttributes);
|
||||
locationsList.addAll(Arrays.asList(configAttributes.getLocations()));
|
||||
classesList.addAll(Arrays.asList(configAttributes.getClasses()));
|
||||
}
|
||||
else {
|
||||
String[] processedLocations = contextLoader.processLocations(configAttributes.getDeclaringClass(),
|
||||
configAttributes.getLocations());
|
||||
locationsList.addAll(Arrays.asList(processedLocations));
|
||||
// Legacy ContextLoaders don't know how to process classes
|
||||
}
|
||||
}
|
||||
|
||||
String[] locations = StringUtils.toStringArray(locationsList);
|
||||
Class<?>[] classes = ClassUtils.toClassArray(classesList);
|
||||
String[] activeProfiles = resolveActiveProfiles(testClass);
|
||||
|
||||
return new MergedContextConfiguration(testClass, locations, classes, activeProfiles, contextLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface for resolving application context resource locations.
|
||||
*
|
||||
* <p>The semantics of the resolved locations are implementation-dependent.
|
||||
*/
|
||||
private static interface LocationsResolver {
|
||||
|
||||
/**
|
||||
* Resolves application context resource locations for the supplied
|
||||
* {@link ContextConfiguration} annotation and the class which declared it.
|
||||
* @param contextConfiguration the <code>ContextConfiguration</code>
|
||||
* for which to resolve resource locations
|
||||
* @param declaringClass the class that declared <code>ContextConfiguration</code>
|
||||
* @return an array of application context resource locations
|
||||
* (can be <code>null</code> or empty)
|
||||
*/
|
||||
String[] resolveLocations(ContextConfiguration contextConfiguration, Class<?> declaringClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>LocationsResolver</code> that resolves locations as Strings,
|
||||
* which are assumed to be path-based resources.
|
||||
*/
|
||||
private static final class ResourcePathLocationsResolver implements LocationsResolver {
|
||||
|
||||
/**
|
||||
* Resolves path-based resources from the {@link ContextConfiguration#locations() locations}
|
||||
* and {@link ContextConfiguration#value() value} attributes of the supplied
|
||||
* {@link ContextConfiguration} annotation.
|
||||
*
|
||||
* <p>Ignores the {@link ContextConfiguration#classes() classes} attribute.
|
||||
* @throws IllegalStateException if both the locations and value
|
||||
* attributes have been declared
|
||||
*/
|
||||
public String[] resolveLocations(ContextConfiguration contextConfiguration, Class<?> declaringClass) {
|
||||
return ContextConfigurationAttributes.resolveLocations(declaringClass, contextConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <code>LocationsResolver</code> that converts classes to fully qualified class names.
|
||||
*/
|
||||
private static final class ClassNameLocationsResolver implements LocationsResolver {
|
||||
|
||||
/**
|
||||
* Resolves class names from the {@link ContextConfiguration#classes() classes}
|
||||
* attribute of the supplied {@link ContextConfiguration} annotation.
|
||||
*
|
||||
* <p>Ignores the {@link ContextConfiguration#locations() locations}
|
||||
* and {@link ContextConfiguration#value() value} attributes.
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ public class MergedContextConfiguration {
|
|||
|
||||
private final ContextLoader contextLoader;
|
||||
|
||||
private final String contextKey;
|
||||
|
||||
|
||||
private static String[] processLocations(String[] locations) {
|
||||
return locations == null ? new String[] {} : locations;
|
||||
|
|
@ -65,14 +67,23 @@ public class MergedContextConfiguration {
|
|||
return StringUtils.toStringArray(sortedProfilesSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a context <code>key</code> from the supplied values.
|
||||
*/
|
||||
private static String generateContextKey(String[] locations, Class<?>[] classes, String[] activeProfiles,
|
||||
ContextLoader contextLoader) {
|
||||
|
||||
String locationsKey = ObjectUtils.nullSafeToString(locations);
|
||||
String classesKey = ObjectUtils.nullSafeToString(classes);
|
||||
String activeProfilesKey = ObjectUtils.nullSafeToString(activeProfiles);
|
||||
String contextLoaderKey = contextLoader == null ? "null" : contextLoader.getClass().getName();
|
||||
|
||||
return String.format("locations = [%s], classes = [%s], activeProfiles = [%s], contextLoader = [%s]",
|
||||
locationsKey, classesKey, activeProfilesKey, contextLoaderKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document MergedContextConfiguration constructor.
|
||||
*
|
||||
* @param testClass
|
||||
* @param locations
|
||||
* @param classes
|
||||
* @param activeProfiles
|
||||
* @param contextLoader
|
||||
*/
|
||||
public MergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes,
|
||||
String[] activeProfiles, ContextLoader contextLoader) {
|
||||
|
|
@ -81,6 +92,7 @@ public class MergedContextConfiguration {
|
|||
this.classes = processClasses(classes);
|
||||
this.activeProfiles = processActiveProfiles(activeProfiles);
|
||||
this.contextLoader = contextLoader;
|
||||
this.contextKey = generateContextKey(this.locations, this.classes, this.activeProfiles, this.contextLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -118,6 +130,13 @@ public class MergedContextConfiguration {
|
|||
return this.contextLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getContextKey().
|
||||
*/
|
||||
public String getContextKey() {
|
||||
return this.contextKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden toString().
|
||||
*/
|
||||
|
|
@ -129,6 +148,7 @@ public class MergedContextConfiguration {
|
|||
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
||||
.append("activeProfiles", ObjectUtils.nullSafeToString(this.activeProfiles))//
|
||||
.append("contextLoader", this.contextLoader)//
|
||||
.append("contextKey", this.contextKey)//
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context;
|
||||
|
||||
/**
|
||||
* Extension of the {@link ContextLoader} API for context loaders that
|
||||
* are aware of the type of context configuration resources that they
|
||||
* support.
|
||||
*
|
||||
* <p>Prior to Spring 3.1, context loaders supported only String-based
|
||||
* resource locations; as of Spring 3.1 context loaders may choose to
|
||||
* support either String-based or Class-based resources (but not both).
|
||||
*
|
||||
* <p>TODO Document how classes are converted into String[] locations
|
||||
* and passed into the corresponding methods in the ContextLoader API.
|
||||
*
|
||||
* <p>If a context loader does not implement this interface it is assumed
|
||||
* that the loader supports String-based resource locations.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface ResourceTypeAwareContextLoader extends ContextLoader {
|
||||
|
||||
/**
|
||||
* Enumeration of context configuration resource types that a given
|
||||
* <code>ContextLoader</code> can support.
|
||||
*
|
||||
* <p>The enum constants have a one-to-one correlation to attributes
|
||||
* of the {@link ContextConfiguration} annotation.
|
||||
*/
|
||||
public static enum ResourceType {
|
||||
|
||||
/**
|
||||
* String-based resource locations.
|
||||
* @see ContextConfiguration#locations
|
||||
* @see ContextConfiguration#value
|
||||
*/
|
||||
LOCATIONS,
|
||||
|
||||
/**
|
||||
* Configuration class resources.
|
||||
* @see ContextConfiguration#classes
|
||||
*/
|
||||
CLASSES;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @return the context configuration resource type supported by this ContextLoader
|
||||
*/
|
||||
ResourceType getResourceType();
|
||||
|
||||
}
|
||||
|
|
@ -26,12 +26,13 @@ import org.springframework.context.ApplicationContext;
|
|||
*/
|
||||
public interface SmartContextLoader extends ContextLoader {
|
||||
|
||||
/**
|
||||
* TODO Document processContextConfigurationAttributes().
|
||||
*/
|
||||
void processContextConfigurationAttributes(ContextConfigurationAttributes configAttributes);
|
||||
|
||||
/**
|
||||
* TODO Document loadContext().
|
||||
*
|
||||
* @param mergedContextConfiguration
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) throws Exception;
|
||||
|
||||
|
|
|
|||
|
|
@ -24,11 +24,10 @@ import org.springframework.context.ApplicationContext;
|
|||
import org.springframework.core.AttributeAccessorSupport;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* TestContext encapsulates the context in which a test is executed, agnostic of
|
||||
* the actual testing framework in use.
|
||||
* <code>TestContext</code> encapsulates the context in which a test is executed,
|
||||
* agnostic of the actual testing framework in use.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
|
|
@ -42,8 +41,6 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
|
||||
private final ContextCache contextCache;
|
||||
|
||||
private final String contextKey;
|
||||
|
||||
private final MergedContextConfiguration mergedContextConfiguration;
|
||||
|
||||
private final Class<?> testClass;
|
||||
|
|
@ -69,8 +66,8 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
* and {@link ContextCache context cache} and parse the corresponding
|
||||
* {@link ContextConfiguration @ContextConfiguration} annotation, if
|
||||
* present.
|
||||
* <p>If the supplied class name for the default ContextLoader is
|
||||
* <code>null</code> or <em>empty</em> and no <code>ContextLoader</code>
|
||||
* <p>If the supplied class name for the default <code>ContextLoader</code>
|
||||
* is <code>null</code> or <em>empty</em> and no <code>ContextLoader</code>
|
||||
* class is explicitly supplied via the
|
||||
* <code>@ContextConfiguration</code> annotation, a
|
||||
* {@link org.springframework.test.context.support.GenericXmlContextLoader
|
||||
|
|
@ -106,14 +103,13 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
}
|
||||
|
||||
this.contextCache = contextCache;
|
||||
this.contextKey = generateContextKey(mergedContextConfiguration);
|
||||
this.mergedContextConfiguration = mergedContextConfiguration;
|
||||
this.testClass = testClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load an <code>ApplicationContext</code> for this test context using the
|
||||
* configured <code>ContextLoader</code> and resource locations.
|
||||
* configured <code>ContextLoader</code> and configuration attributes.
|
||||
* @throws Exception if an error occurs while loading the application context
|
||||
*/
|
||||
private ApplicationContext loadApplicationContext() throws Exception {
|
||||
|
|
@ -137,26 +133,6 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a context <code>key</code> from information stored in the
|
||||
* {@link MergedContextConfiguration} for this <code>TestContext</code>.
|
||||
*/
|
||||
private String generateContextKey(MergedContextConfiguration mergedContextConfiguration) {
|
||||
|
||||
String[] locations = mergedContextConfiguration.getLocations();
|
||||
Class<?>[] classes = mergedContextConfiguration.getClasses();
|
||||
String[] activeProfiles = mergedContextConfiguration.getActiveProfiles();
|
||||
ContextLoader contextLoader = mergedContextConfiguration.getContextLoader();
|
||||
|
||||
String locationsKey = ObjectUtils.nullSafeToString(locations);
|
||||
String classesKey = ObjectUtils.nullSafeToString(classes);
|
||||
String activeProfilesKey = ObjectUtils.nullSafeToString(activeProfiles);
|
||||
String contextLoaderKey = contextLoader == null ? "null" : contextLoader.getClass().getName();
|
||||
|
||||
return String.format("locations = [%s], classes = [%s], activeProfiles = [%s], contextLoader = [%s]",
|
||||
locationsKey, classesKey, activeProfilesKey, contextLoaderKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the {@link ApplicationContext application context} for this test
|
||||
* context, possibly cached.
|
||||
|
|
@ -165,6 +141,7 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
* application context
|
||||
*/
|
||||
public ApplicationContext getApplicationContext() {
|
||||
String contextKey = mergedContextConfiguration.getContextKey();
|
||||
synchronized (contextCache) {
|
||||
ApplicationContext context = contextCache.get(contextKey);
|
||||
if (context == null) {
|
||||
|
|
@ -239,7 +216,9 @@ public class TestContext extends AttributeAccessorSupport {
|
|||
* replacing a bean definition).
|
||||
*/
|
||||
public void markApplicationContextDirty() {
|
||||
contextCache.setDirty(contextKey);
|
||||
synchronized (contextCache) {
|
||||
contextCache.setDirty(mergedContextConfiguration.getContextKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ package org.springframework.test.context.support;
|
|||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.ResourceTypeAwareContextLoader;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
|
@ -39,7 +39,17 @@ import org.springframework.util.StringUtils;
|
|||
* @see #generateDefaultLocations
|
||||
* @see #modifyLocations
|
||||
*/
|
||||
public abstract class AbstractContextLoader implements SmartContextLoader, ResourceTypeAwareContextLoader {
|
||||
public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
|
||||
/**
|
||||
* TODO Document processContextConfigurationAttributes().
|
||||
*/
|
||||
public void processContextConfigurationAttributes(ContextConfigurationAttributes configAttributes) {
|
||||
String[] processedLocations = processLocations(configAttributes.getDeclaringClass(),
|
||||
configAttributes.getLocations());
|
||||
|
||||
configAttributes.setLocations(processedLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the supplied <code>locations</code> are <code>null</code> or
|
||||
|
|
@ -142,13 +152,4 @@ public abstract class AbstractContextLoader implements SmartContextLoader, Resou
|
|||
*/
|
||||
protected abstract String getResourceSuffix();
|
||||
|
||||
/**
|
||||
* The default implementation returns {@link ResourceType#LOCATIONS}.
|
||||
* <p>Can be overridden by subclasses.
|
||||
* @since 3.1
|
||||
*/
|
||||
public ResourceType getResourceType() {
|
||||
return ResourceType.LOCATIONS;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,12 +20,11 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
|
@ -49,25 +48,21 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
|
||||
|
||||
/**
|
||||
* TODO Document loadContext().
|
||||
* TODO Document loadContext(MergedContextConfiguration).
|
||||
*
|
||||
* @see org.springframework.test.context.SmartContextLoader#loadContext(org.springframework.test.context.MergedContextConfiguration)
|
||||
* @see SmartContextLoader#loadContext(MergedContextConfiguration)
|
||||
*/
|
||||
public final ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) throws Exception {
|
||||
public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration)
|
||||
throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Loading ApplicationContext for merged context configuration [%s].",
|
||||
mergedContextConfiguration));
|
||||
}
|
||||
|
||||
String[] locations = mergedContextConfiguration.getLocations();
|
||||
Assert.notNull(locations, "Can not load an ApplicationContext with a NULL 'locations' array. "
|
||||
+ "Consider annotating your test class with @ContextConfiguration.");
|
||||
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
context.getEnvironment().setActiveProfiles(mergedContextConfiguration.getActiveProfiles());
|
||||
prepareContext(context);
|
||||
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
||||
loadBeanDefinitions(context, locations);
|
||||
loadBeanDefinitions(context, mergedContextConfiguration);
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
customizeContext(context);
|
||||
context.refresh();
|
||||
|
|
@ -84,7 +79,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
* prepare the context.</li>
|
||||
* <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to
|
||||
* allow for customizing the context's <code>DefaultListableBeanFactory</code>.</li>
|
||||
* <li>Delegates to {@link #loadBeanDefinitions(GenericApplicationContext, String...)}
|
||||
* <li>TODO Update/revert documentation... Delegates to {@link #loadBeanDefinitions(GenericApplicationContext, String...)}
|
||||
* to populate the context from the specified config locations.</li>
|
||||
* <li>Delegates to {@link AnnotationConfigUtils} for
|
||||
* {@link AnnotationConfigUtils#registerAnnotationConfigProcessors registering}
|
||||
|
|
@ -106,7 +101,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
prepareContext(context);
|
||||
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
||||
loadBeanDefinitions(context, locations);
|
||||
createBeanDefinitionReader(context).loadBeanDefinitions(locations);
|
||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||
customizeContext(context);
|
||||
context.refresh();
|
||||
|
|
@ -154,12 +149,13 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
* and override this method to provide a custom strategy for loading or
|
||||
* registering bean definitions.
|
||||
* @param context the context into which the bean definitions should be loaded
|
||||
* @param locations the resource locations from which to load the bean definitions
|
||||
* @param mergedContextConfiguration TODO Document parameters.
|
||||
* @since 3.1
|
||||
* @see #loadContext
|
||||
*/
|
||||
protected void loadBeanDefinitions(GenericApplicationContext context, String... locations) {
|
||||
createBeanDefinitionReader(context).loadBeanDefinitions(locations);
|
||||
protected void loadBeanDefinitions(GenericApplicationContext context,
|
||||
MergedContextConfiguration mergedContextConfiguration) {
|
||||
createBeanDefinitionReader(context).loadBeanDefinitions(mergedContextConfiguration.getLocations());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -167,7 +163,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
|||
* loading bean definitions into the supplied {@link GenericApplicationContext context}.
|
||||
* @param context the context for which the BeanDefinitionReader should be created
|
||||
* @return a BeanDefinitionReader for the supplied context
|
||||
* @see #loadBeanDefinitions
|
||||
* @see #loadContext(String...)
|
||||
* @see BeanDefinitionReader
|
||||
*/
|
||||
protected abstract BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context);
|
||||
|
|
|
|||
|
|
@ -16,12 +16,16 @@
|
|||
|
||||
package org.springframework.test.context.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
|
|
@ -30,13 +34,6 @@ import org.springframework.util.ObjectUtils;
|
|||
* registers bean definitions from
|
||||
* {@link org.springframework.context.annotation.Configuration configuration classes}.
|
||||
*
|
||||
* <p>This <code>ContextLoader</code> supports class-based context configuration
|
||||
* {@link #getResourceType() resources} as opposed to string-based resources.
|
||||
* Consequently, <em>locations</em> (as discussed in the {@link ContextLoader}
|
||||
* API and superclasses) are interpreted as fully qualified class names
|
||||
* in the context of this class. The documentation and method parameters
|
||||
* reflect this.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
*/
|
||||
|
|
@ -46,6 +43,21 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
|||
|
||||
|
||||
/**
|
||||
* TODO Document overridden processContextConfigurationAttributes().
|
||||
*
|
||||
* @see org.springframework.test.context.SmartContextLoader#processContextConfigurationAttributes
|
||||
*/
|
||||
public void processContextConfigurationAttributes(ContextConfigurationAttributes configAttributes) {
|
||||
if (ObjectUtils.isEmpty(configAttributes.getClasses()) && isGenerateDefaultClasses()) {
|
||||
Class<?>[] defaultConfigurationClasses = generateDefaultConfigurationClasses(configAttributes.getDeclaringClass());
|
||||
configAttributes.setClasses(defaultConfigurationClasses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Update documentation regarding SmartContextLoader SPI.
|
||||
*
|
||||
* <p>
|
||||
* Registers {@link org.springframework.context.annotation.Configuration configuration classes}
|
||||
* in the supplied {@link GenericApplicationContext context} from the specified
|
||||
* class names.
|
||||
|
|
@ -64,21 +76,9 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
|||
* @throws IllegalArgumentException if a supplied class name does not represent a class
|
||||
*/
|
||||
@Override
|
||||
protected void loadBeanDefinitions(GenericApplicationContext context, String... classNames) {
|
||||
|
||||
Class<?>[] configClasses = new Class<?>[classNames.length];
|
||||
|
||||
for (int i = 0; i < classNames.length; i++) {
|
||||
String className = classNames[i];
|
||||
try {
|
||||
configClasses[i] = (Class<?>) context.getClassLoader().loadClass(className);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"The supplied class name [%s] does not represent a class.", className), e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void loadBeanDefinitions(GenericApplicationContext context,
|
||||
MergedContextConfiguration mergedContextConfiguration) {
|
||||
Class<?>[] configClasses = mergedContextConfiguration.getClasses();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Registering configuration classes: " + ObjectUtils.nullSafeToString(configClasses));
|
||||
}
|
||||
|
|
@ -86,40 +86,10 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns <code>null</code>; intended as a <em>no-op</em> operation.
|
||||
* TODO Document isGenerateDefaultClasses().
|
||||
*/
|
||||
@Override
|
||||
protected BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the default {@link org.springframework.context.annotation.Configuration configuration class}
|
||||
* names array based on the supplied class.
|
||||
*
|
||||
* <p>For example, if the supplied class is <code>com.example.MyTest</code>,
|
||||
* the generated array will contain a single string with a value of
|
||||
* "com.example.MyTest<code><suffix></code>",
|
||||
* where <code><suffix></code> is the value of the
|
||||
* {@link #getResourceSuffix() resource suffix} string.
|
||||
* @param clazz the class for which the default configuration class names are to be generated
|
||||
* @return an array of default configuration class names
|
||||
* @see #getResourceSuffix()
|
||||
*/
|
||||
@Override
|
||||
protected String[] generateDefaultLocations(Class<?> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
String suffix = getResourceSuffix();
|
||||
Assert.hasText(suffix, "Resource suffix must not be empty");
|
||||
return new String[] { clazz.getName() + suffix };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the supplied class names unmodified.
|
||||
*/
|
||||
@Override
|
||||
protected String[] modifyLocations(Class<?> clazz, String... classNames) {
|
||||
return classNames;
|
||||
protected boolean isGenerateDefaultClasses() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -133,17 +103,64 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
|||
*
|
||||
* @see #generateDefaultLocations(Class)
|
||||
*/
|
||||
@Override
|
||||
protected String getResourceSuffix() {
|
||||
protected String getConfigurationClassNameSuffix() {
|
||||
return "$ContextConfiguration";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link ResourceType#CLASSES}.
|
||||
* TODO Document generateDefaultConfigurationClasses().
|
||||
*/
|
||||
protected Class<?>[] generateDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||
Assert.notNull(declaringClass, "Declaring class must not be null");
|
||||
String suffix = getConfigurationClassNameSuffix();
|
||||
Assert.hasText(suffix, "Configuration class name suffix must not be empty");
|
||||
String className = declaringClass.getName() + suffix;
|
||||
|
||||
List<Class<?>> configClasses = new ArrayList<Class<?>>();
|
||||
try {
|
||||
configClasses.add((Class<?>) getClass().getClassLoader().loadClass(className));
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
logger.warn(String.format("Cannot load @Configuration class with generated class name [%s].", className), e);
|
||||
}
|
||||
|
||||
return configClasses.toArray(new Class<?>[configClasses.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden createBeanDefinitionReader().
|
||||
*/
|
||||
@Override
|
||||
public final ResourceType getResourceType() {
|
||||
return ResourceType.CLASSES;
|
||||
protected BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {
|
||||
throw new UnsupportedOperationException(
|
||||
"AnnotationConfigContextLoader does not support the createBeanDefinitionReader(GenericApplicationContext) method");
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden generateDefaultLocations().
|
||||
*/
|
||||
@Override
|
||||
protected String[] generateDefaultLocations(Class<?> clazz) {
|
||||
throw new UnsupportedOperationException(
|
||||
"AnnotationConfigContextLoader does not support the generateDefaultLocations(Class) method");
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden modifyLocations().
|
||||
*/
|
||||
@Override
|
||||
protected String[] modifyLocations(Class<?> clazz, String... locations) {
|
||||
throw new UnsupportedOperationException(
|
||||
"AnnotationConfigContextLoader does not support the modifyLocations(Class, String...) method");
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden getResourceSuffix().
|
||||
*/
|
||||
@Override
|
||||
protected String getResourceSuffix() {
|
||||
throw new UnsupportedOperationException(
|
||||
"AnnotationConfigContextLoader does not support the getResourceSuffix() method");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import org.springframework.test.context.support.GenericXmlContextLoader;
|
|||
*/
|
||||
public class ContextLoaderUtilsTests {
|
||||
|
||||
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[] {};
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[] {};
|
||||
|
||||
|
||||
|
|
@ -48,7 +49,7 @@ public class ContextLoaderUtilsTests {
|
|||
assertArrayEquals(expectedLocations, attributes.getLocations());
|
||||
assertArrayEquals(expectedClasses, attributes.getClasses());
|
||||
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
|
||||
assertEquals(expectedContextLoaderClass, attributes.getContextLoader());
|
||||
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
|
||||
}
|
||||
|
||||
private void assertFooAttributes(ContextConfigurationAttributes attributes) {
|
||||
|
|
@ -62,12 +63,14 @@ public class ContextLoaderUtilsTests {
|
|||
}
|
||||
|
||||
private void assertMergedContextConfiguration(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass,
|
||||
String[] expectedLocations, Class<? extends ContextLoader> expectedContextLoaderClass) {
|
||||
String[] expectedLocations, Class<?>[] expectedClasses,
|
||||
Class<? extends ContextLoader> expectedContextLoaderClass) {
|
||||
assertNotNull(mergedConfig);
|
||||
assertEquals(expectedTestClass, mergedConfig.getTestClass());
|
||||
assertNotNull(mergedConfig.getLocations());
|
||||
assertArrayEquals(expectedLocations, mergedConfig.getLocations());
|
||||
assertNotNull(mergedConfig.getClasses());
|
||||
assertArrayEquals(expectedClasses, mergedConfig.getClasses());
|
||||
assertNotNull(mergedConfig.getActiveProfiles());
|
||||
assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass());
|
||||
}
|
||||
|
|
@ -82,7 +85,7 @@ public class ContextLoaderUtilsTests {
|
|||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(BareAnnotations.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(1, attributesList.size());
|
||||
assertAttributes(attributesList.get(0), BareAnnotations.class, EMPTY_STRING_ARRAY, new Class<?>[] {},
|
||||
assertAttributes(attributesList.get(0), BareAnnotations.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY,
|
||||
ContextLoader.class, true);
|
||||
}
|
||||
|
||||
|
|
@ -117,7 +120,7 @@ public class ContextLoaderUtilsTests {
|
|||
mergedConfig,
|
||||
testClass,
|
||||
new String[] { "classpath:/org/springframework/test/context/ContextLoaderUtilsTests$BareAnnotations-context.xml" },
|
||||
GenericXmlContextLoader.class);
|
||||
EMPTY_CLASS_ARRAY, GenericXmlContextLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -126,31 +129,28 @@ public class ContextLoaderUtilsTests {
|
|||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
||||
GenericXmlContextLoader.class);
|
||||
new Class<?>[] { FooConfig.class }, GenericXmlContextLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAnnotationAndOverriddenContexLoader() {
|
||||
public void buildMergedContextConfigurationWithLocalAnnotationAndOverriddenContextLoader() {
|
||||
Class<?> testClass = Foo.class;
|
||||
Class<? extends ContextLoader> expectedContextLoaderClass = GenericPropertiesContextLoader.class;
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass,
|
||||
expectedContextLoaderClass.getName());
|
||||
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
||||
expectedContextLoaderClass);
|
||||
new Class<?>[] { FooConfig.class }, expectedContextLoaderClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAndInheritedAnnotations() {
|
||||
Class<?> testClass = Bar.class;
|
||||
String[] expectedLocations = new String[] { "/foo.xml", "/bar.xml" };
|
||||
Class<?>[] expectedClasses = new Class<?>[] { FooConfig.class, BarConfig.class };
|
||||
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||
|
||||
// TODO Assert @Configuration classes instead of locations
|
||||
String[] expectedLocations = new String[] {
|
||||
"org.springframework.test.context.ContextLoaderUtilsTests$FooConfig",
|
||||
"org.springframework.test.context.ContextLoaderUtilsTests$BarConfig" };
|
||||
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, expectedLocations,
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, expectedLocations, expectedClasses,
|
||||
AnnotationConfigContextLoader.class);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
|||
|
||||
/**
|
||||
* Unit tests for verifying proper behavior of the {@link ContextCache} in
|
||||
* conjunction with cache keys generated in {@link TestContext}.
|
||||
* conjunction with cache keys used in {@link TestContext}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2011 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.
|
||||
|
|
@ -22,8 +22,11 @@ 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.BeanOverridingDefaultConfigClassesInheritedTests;
|
||||
import org.springframework.test.context.junit4.annotation.BeanOverridingExplicitConfigClassesInheritedTests;
|
||||
import org.springframework.test.context.junit4.annotation.DefaultConfigClassesBaseTests;
|
||||
import org.springframework.test.context.junit4.annotation.DefaultConfigClassesInheritedTests;
|
||||
import org.springframework.test.context.junit4.annotation.ExplicitConfigClassesInheritedTests;
|
||||
import org.springframework.test.context.junit4.orm.HibernateSessionFlushingTests;
|
||||
import org.springframework.test.context.junit4.profile.annotation.DefaultProfileAnnotationConfigTests;
|
||||
import org.springframework.test.context.junit4.profile.annotation.DevProfileAnnotationConfigTests;
|
||||
|
|
@ -31,20 +34,16 @@ import org.springframework.test.context.junit4.profile.xml.DefaultProfileXmlConf
|
|||
import org.springframework.test.context.junit4.profile.xml.DevProfileXmlConfigTests;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* JUnit 4 based test suite for tests involving {@link SpringJUnit4ClassRunner}
|
||||
* and the <em>Spring TestContext Framework</em>.
|
||||
* </p>
|
||||
* <p>
|
||||
* This test suite serves a dual purpose of verifying that tests run with
|
||||
* {@link SpringJUnit4ClassRunner} can be used in conjunction with JUnit 4's
|
||||
* JUnit test suite for tests involving {@link SpringJUnit4ClassRunner} and the
|
||||
* <em>Spring TestContext Framework</em>.
|
||||
*
|
||||
* <p>This test suite serves a dual purpose of verifying that tests run with
|
||||
* {@link SpringJUnit4ClassRunner} can be used in conjunction with JUnit's
|
||||
* {@link Suite} runner.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that tests included in this suite will be executed at least twice if run
|
||||
* from an automated build process, test runner, etc. that is configured to run
|
||||
* tests based on a "*Tests.class" pattern match.
|
||||
* </p>
|
||||
*
|
||||
* <p>Note that tests included in this suite will be executed at least twice if
|
||||
* run from an automated build process, test runner, etc. that is configured to
|
||||
* run tests based on a "*Tests.class" pattern match.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 2.5
|
||||
|
|
@ -58,6 +57,9 @@ StandardJUnit4FeaturesTests.class,//
|
|||
AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,//
|
||||
DefaultConfigClassesBaseTests.class,//
|
||||
DefaultConfigClassesInheritedTests.class,//
|
||||
BeanOverridingDefaultConfigClassesInheritedTests.class,//
|
||||
ExplicitConfigClassesInheritedTests.class,//
|
||||
BeanOverridingExplicitConfigClassesInheritedTests.class,//
|
||||
DefaultProfileAnnotationConfigTests.class,//
|
||||
DevProfileAnnotationConfigTests.class, //
|
||||
DefaultProfileXmlConfigTests.class,//
|
||||
|
|
|
|||
Loading…
Reference in New Issue