[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 git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4573 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
7613a1fc50
commit
b617210d50
|
|
@ -34,13 +34,13 @@ public class ContextConfigurationAttributes {
|
||||||
|
|
||||||
private final Class<?> declaringClass;
|
private final Class<?> declaringClass;
|
||||||
|
|
||||||
private final String[] locations;
|
private String[] locations;
|
||||||
|
|
||||||
private final Class<?>[] classes;
|
private Class<?>[] classes;
|
||||||
|
|
||||||
private final boolean inheritLocations;
|
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.
|
* TODO Document ContextConfigurationAttributes constructor.
|
||||||
*
|
|
||||||
* @param declaringClass
|
|
||||||
* @param contextConfiguration
|
|
||||||
*/
|
*/
|
||||||
public ContextConfigurationAttributes(Class<?> declaringClass, ContextConfiguration contextConfiguration) {
|
public ContextConfigurationAttributes(Class<?> declaringClass, ContextConfiguration contextConfiguration) {
|
||||||
this(declaringClass, resolveLocations(declaringClass, contextConfiguration), contextConfiguration.classes(),
|
this(declaringClass, resolveLocations(declaringClass, contextConfiguration), contextConfiguration.classes(),
|
||||||
|
|
@ -83,20 +80,14 @@ public class ContextConfigurationAttributes {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Document ContextConfigurationAttributes constructor.
|
* TODO Document ContextConfigurationAttributes constructor.
|
||||||
*
|
|
||||||
* @param declaringClass
|
|
||||||
* @param locations
|
|
||||||
* @param classes
|
|
||||||
* @param inheritLocations
|
|
||||||
* @param contextLoader
|
|
||||||
*/
|
*/
|
||||||
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
|
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
|
||||||
boolean inheritLocations, Class<? extends ContextLoader> contextLoader) {
|
boolean inheritLocations, Class<? extends ContextLoader> contextLoaderClass) {
|
||||||
this.declaringClass = declaringClass;
|
this.declaringClass = declaringClass;
|
||||||
this.locations = locations;
|
this.locations = locations;
|
||||||
this.classes = classes;
|
this.classes = classes;
|
||||||
this.inheritLocations = inheritLocations;
|
this.inheritLocations = inheritLocations;
|
||||||
this.contextLoader = contextLoader;
|
this.contextLoaderClass = contextLoaderClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -113,6 +104,13 @@ public class ContextConfigurationAttributes {
|
||||||
return this.locations;
|
return this.locations;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Document setLocations().
|
||||||
|
*/
|
||||||
|
public void setLocations(String[] locations) {
|
||||||
|
this.locations = locations;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Document getClasses().
|
* TODO Document getClasses().
|
||||||
*/
|
*/
|
||||||
|
|
@ -120,6 +118,13 @@ public class ContextConfigurationAttributes {
|
||||||
return this.classes;
|
return this.classes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Document setClasses().
|
||||||
|
*/
|
||||||
|
public void setClasses(Class<?>[] classes) {
|
||||||
|
this.classes = classes;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Document isInheritLocations().
|
* TODO Document isInheritLocations().
|
||||||
*/
|
*/
|
||||||
|
|
@ -128,10 +133,10 @@ public class ContextConfigurationAttributes {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Document getContextLoader().
|
* TODO Document getContextLoaderClass().
|
||||||
*/
|
*/
|
||||||
public Class<? extends ContextLoader> getContextLoader() {
|
public Class<? extends ContextLoader> getContextLoaderClass() {
|
||||||
return this.contextLoader;
|
return this.contextLoaderClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -144,7 +149,7 @@ public class ContextConfigurationAttributes {
|
||||||
.append("locations", ObjectUtils.nullSafeToString(this.locations))//
|
.append("locations", ObjectUtils.nullSafeToString(this.locations))//
|
||||||
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
||||||
.append("inheritLocations", this.inheritLocations)//
|
.append("inheritLocations", this.inheritLocations)//
|
||||||
.append("contextLoader", this.contextLoader)//
|
.append("contextLoaderClass", this.contextLoaderClass)//
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,9 @@ import java.util.Set;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.test.context.ResourceTypeAwareContextLoader.ResourceType;
|
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
|
|
@ -40,21 +39,53 @@ import org.springframework.util.StringUtils;
|
||||||
* @since 3.1
|
* @since 3.1
|
||||||
* @see ContextLoader
|
* @see ContextLoader
|
||||||
* @see ContextConfiguration
|
* @see ContextConfiguration
|
||||||
|
* @see ContextConfigurationAttributes
|
||||||
* @see ActiveProfiles
|
* @see ActiveProfiles
|
||||||
* @see MergedContextConfiguration
|
* @see MergedContextConfiguration
|
||||||
*/
|
*/
|
||||||
abstract class ContextLoaderUtils {
|
abstract class ContextLoaderUtils {
|
||||||
|
|
||||||
// TODO Consider refactoring ContextLoaderUtils into a stateful
|
|
||||||
// ContextLoaderResolver.
|
|
||||||
|
|
||||||
private static final Log logger = LogFactory.getLog(ContextLoaderUtils.class);
|
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 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
|
* 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})
|
* default context loader class name ({@value #STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME})
|
||||||
* will be used. For details on the class resolution process, see
|
* will be used. For details on the class resolution process, see
|
||||||
* {@link #resolveContextLoaderClass(Class, String)}.
|
* {@link #resolveContextLoaderClass(Class, String)}.
|
||||||
|
*
|
||||||
* @param testClass the test class for which the <code>ContextLoader</code>
|
* @param testClass the test class for which the <code>ContextLoader</code>
|
||||||
* should be resolved (must not be <code>null</code>)
|
* should be resolved (must not be <code>null</code>)
|
||||||
|
* @param configAttributesList TODO Document parameter
|
||||||
* @param defaultContextLoaderClassName the name of the default
|
* @param defaultContextLoaderClassName the name of the default
|
||||||
* <code>ContextLoader</code> class to use (may be <code>null</code>)
|
* <code>ContextLoader</code> class to use (may be <code>null</code>)
|
||||||
|
*
|
||||||
* @return the resolved <code>ContextLoader</code> for the supplied
|
* @return the resolved <code>ContextLoader</code> for the supplied
|
||||||
* <code>testClass</code> (never <code>null</code>)
|
* <code>testClass</code> (never <code>null</code>)
|
||||||
* @see #resolveContextLoaderClass(Class, String)
|
* @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.notNull(testClass, "Test class must not be null");
|
||||||
|
Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty");
|
||||||
|
|
||||||
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
|
if (!StringUtils.hasText(defaultContextLoaderClassName)) {
|
||||||
defaultContextLoaderClassName = STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
defaultContextLoaderClassName = STANDARD_DEFAULT_CONTEXT_LOADER_CLASS_NAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass,
|
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass, configAttributesList,
|
||||||
defaultContextLoaderClassName);
|
defaultContextLoaderClassName);
|
||||||
|
|
||||||
return (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass);
|
return (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass);
|
||||||
|
|
@ -103,52 +139,46 @@ abstract class ContextLoaderUtils {
|
||||||
* with the supplied <code>defaultContextLoaderClassName</code>.</li>
|
* with the supplied <code>defaultContextLoaderClassName</code>.</li>
|
||||||
* </ol>
|
* </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>
|
* class; must not be <code>null</code>
|
||||||
|
* @param configAttributesList TODO Document parameter
|
||||||
* @param defaultContextLoaderClassName the name of the default
|
* @param defaultContextLoaderClassName the name of the default
|
||||||
* <code>ContextLoader</code> class to use; must not be <code>null</code> or empty
|
* <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
|
* @return the <code>ContextLoader</code> class to use for the specified class
|
||||||
* (never <code>null</code>)
|
* (never <code>null</code>)
|
||||||
* @throws IllegalArgumentException if {@link ContextConfiguration
|
* @throws IllegalArgumentException if {@link ContextConfiguration
|
||||||
* @ContextConfiguration} is not <em>present</em> on the supplied class
|
* @ContextConfiguration} is not <em>present</em> on the supplied class
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> clazz, String defaultContextLoaderClassName) {
|
static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> testClass,
|
||||||
Assert.notNull(clazz, "Class must not be null");
|
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");
|
Assert.hasText(defaultContextLoaderClassName, "Default ContextLoader class name must not be null or empty");
|
||||||
|
|
||||||
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
|
for (ContextConfigurationAttributes configAttributes : configAttributesList) {
|
||||||
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()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("Processing ContextLoader for @ContextConfiguration [" + contextConfiguration
|
logger.trace(String.format(
|
||||||
+ "] and declaring class [" + declaringClass + "]");
|
"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 (!ContextLoader.class.equals(contextLoaderClass)) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Found explicit ContextLoader [" + contextLoaderClass
|
logger.debug(String.format(
|
||||||
+ "] for @ContextConfiguration [" + contextConfiguration + "] and declaring class ["
|
"Found explicit ContextLoader class [%s] for context configuration attributes [%s] and test class [%s]",
|
||||||
+ declaringClass + "]");
|
contextLoaderClass, configAttributes, testClass));
|
||||||
}
|
}
|
||||||
return contextLoaderClass;
|
return contextLoaderClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType,
|
|
||||||
declaringClass.getSuperclass());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
ContextConfiguration contextConfiguration = clazz.getAnnotation(annotationType);
|
logger.trace(String.format("Using default ContextLoader class [%s] for test class [%s]",
|
||||||
logger.trace("Using default ContextLoader class [" + defaultContextLoaderClassName
|
defaultContextLoaderClassName, testClass));
|
||||||
+ "] for @ContextConfiguration [" + contextConfiguration + "] and class [" + clazz + "]");
|
|
||||||
}
|
}
|
||||||
return (Class<? extends ContextLoader>) ContextLoaderUtils.class.getClassLoader().loadClass(
|
return (Class<? extends ContextLoader>) ContextLoaderUtils.class.getClassLoader().loadClass(
|
||||||
defaultContextLoaderClassName);
|
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
|
* Resolves <em>active bean definition profiles</em> for the supplied
|
||||||
* {@link Class class}.
|
* {@link Class class}.
|
||||||
|
|
@ -231,6 +202,7 @@ abstract class ContextLoaderUtils {
|
||||||
*
|
*
|
||||||
* @param clazz the class for which to resolve the active profiles (must
|
* @param clazz the class for which to resolve the active profiles (must
|
||||||
* not be <code>null</code>)
|
* not be <code>null</code>)
|
||||||
|
*
|
||||||
* @return the set of active profiles for the specified class, including
|
* @return the set of active profiles for the specified class, including
|
||||||
* active profiles from superclasses if appropriate (never <code>null</code>)
|
* active profiles from superclasses if appropriate (never <code>null</code>)
|
||||||
*/
|
*/
|
||||||
|
|
@ -284,136 +256,77 @@ abstract class ContextLoaderUtils {
|
||||||
return StringUtils.toStringArray(activeProfiles);
|
return StringUtils.toStringArray(activeProfiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* TODO Document resolveContextConfigurationAttributes().
|
* 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.
|
||||||
*
|
*
|
||||||
* @param clazz
|
* <p>Note that the {@link ContextConfiguration#inheritLocations()
|
||||||
* @return
|
* 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().
|
* TODO Document buildMergedContextConfiguration().
|
||||||
*
|
|
||||||
* @param testClass
|
|
||||||
* @param defaultContextLoaderClassName
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass,
|
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass,
|
||||||
String defaultContextLoaderClassName) {
|
String defaultContextLoaderClassName) {
|
||||||
|
|
||||||
ContextLoader contextLoader = resolveContextLoader(testClass, defaultContextLoaderClassName);
|
List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass);
|
||||||
|
|
||||||
// TODO Merge locations from List<ContextConfigurationAttributes>
|
ContextLoader contextLoader = resolveContextLoader(testClass, configAttributesList,
|
||||||
String[] locations = resolveContextLocations(contextLoader, testClass);
|
defaultContextLoaderClassName);
|
||||||
|
|
||||||
// TODO Merge classes from List<ContextConfigurationAttributes>
|
// Algorithm:
|
||||||
Class<?>[] classes = {};
|
// - 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);
|
String[] activeProfiles = resolveActiveProfiles(testClass);
|
||||||
|
|
||||||
return new MergedContextConfiguration(testClass, locations, classes, activeProfiles, contextLoader);
|
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 ContextLoader contextLoader;
|
||||||
|
|
||||||
|
private final String contextKey;
|
||||||
|
|
||||||
|
|
||||||
private static String[] processLocations(String[] locations) {
|
private static String[] processLocations(String[] locations) {
|
||||||
return locations == null ? new String[] {} : locations;
|
return locations == null ? new String[] {} : locations;
|
||||||
|
|
@ -65,14 +67,23 @@ public class MergedContextConfiguration {
|
||||||
return StringUtils.toStringArray(sortedProfilesSet);
|
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.
|
* TODO Document MergedContextConfiguration constructor.
|
||||||
*
|
|
||||||
* @param testClass
|
|
||||||
* @param locations
|
|
||||||
* @param classes
|
|
||||||
* @param activeProfiles
|
|
||||||
* @param contextLoader
|
|
||||||
*/
|
*/
|
||||||
public MergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes,
|
public MergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes,
|
||||||
String[] activeProfiles, ContextLoader contextLoader) {
|
String[] activeProfiles, ContextLoader contextLoader) {
|
||||||
|
|
@ -81,6 +92,7 @@ public class MergedContextConfiguration {
|
||||||
this.classes = processClasses(classes);
|
this.classes = processClasses(classes);
|
||||||
this.activeProfiles = processActiveProfiles(activeProfiles);
|
this.activeProfiles = processActiveProfiles(activeProfiles);
|
||||||
this.contextLoader = contextLoader;
|
this.contextLoader = contextLoader;
|
||||||
|
this.contextKey = generateContextKey(this.locations, this.classes, this.activeProfiles, this.contextLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -118,6 +130,13 @@ public class MergedContextConfiguration {
|
||||||
return this.contextLoader;
|
return this.contextLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Document getContextKey().
|
||||||
|
*/
|
||||||
|
public String getContextKey() {
|
||||||
|
return this.contextKey;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Document overridden toString().
|
* TODO Document overridden toString().
|
||||||
*/
|
*/
|
||||||
|
|
@ -129,6 +148,7 @@ public class MergedContextConfiguration {
|
||||||
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
||||||
.append("activeProfiles", ObjectUtils.nullSafeToString(this.activeProfiles))//
|
.append("activeProfiles", ObjectUtils.nullSafeToString(this.activeProfiles))//
|
||||||
.append("contextLoader", this.contextLoader)//
|
.append("contextLoader", this.contextLoader)//
|
||||||
|
.append("contextKey", this.contextKey)//
|
||||||
.toString();
|
.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 {
|
public interface SmartContextLoader extends ContextLoader {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO Document processContextConfigurationAttributes().
|
||||||
|
*/
|
||||||
|
void processContextConfigurationAttributes(ContextConfigurationAttributes configAttributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TODO Document loadContext().
|
* TODO Document loadContext().
|
||||||
*
|
|
||||||
* @param mergedContextConfiguration
|
|
||||||
* @return
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) 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.AttributeAccessorSupport;
|
||||||
import org.springframework.core.style.ToStringCreator;
|
import org.springframework.core.style.ToStringCreator;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TestContext encapsulates the context in which a test is executed, agnostic of
|
* <code>TestContext</code> encapsulates the context in which a test is executed,
|
||||||
* the actual testing framework in use.
|
* agnostic of the actual testing framework in use.
|
||||||
*
|
*
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
|
|
@ -42,8 +41,6 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
|
|
||||||
private final ContextCache contextCache;
|
private final ContextCache contextCache;
|
||||||
|
|
||||||
private final String contextKey;
|
|
||||||
|
|
||||||
private final MergedContextConfiguration mergedContextConfiguration;
|
private final MergedContextConfiguration mergedContextConfiguration;
|
||||||
|
|
||||||
private final Class<?> testClass;
|
private final Class<?> testClass;
|
||||||
|
|
@ -69,8 +66,8 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
* and {@link ContextCache context cache} and parse the corresponding
|
* and {@link ContextCache context cache} and parse the corresponding
|
||||||
* {@link ContextConfiguration @ContextConfiguration} annotation, if
|
* {@link ContextConfiguration @ContextConfiguration} annotation, if
|
||||||
* present.
|
* present.
|
||||||
* <p>If the supplied class name for the default ContextLoader is
|
* <p>If the supplied class name for the default <code>ContextLoader</code>
|
||||||
* <code>null</code> or <em>empty</em> and no <code>ContextLoader</code>
|
* is <code>null</code> or <em>empty</em> and no <code>ContextLoader</code>
|
||||||
* class is explicitly supplied via the
|
* class is explicitly supplied via the
|
||||||
* <code>@ContextConfiguration</code> annotation, a
|
* <code>@ContextConfiguration</code> annotation, a
|
||||||
* {@link org.springframework.test.context.support.GenericXmlContextLoader
|
* {@link org.springframework.test.context.support.GenericXmlContextLoader
|
||||||
|
|
@ -106,14 +103,13 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.contextCache = contextCache;
|
this.contextCache = contextCache;
|
||||||
this.contextKey = generateContextKey(mergedContextConfiguration);
|
|
||||||
this.mergedContextConfiguration = mergedContextConfiguration;
|
this.mergedContextConfiguration = mergedContextConfiguration;
|
||||||
this.testClass = testClass;
|
this.testClass = testClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load an <code>ApplicationContext</code> for this test context using the
|
* 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
|
* @throws Exception if an error occurs while loading the application context
|
||||||
*/
|
*/
|
||||||
private ApplicationContext loadApplicationContext() throws Exception {
|
private ApplicationContext loadApplicationContext() throws Exception {
|
||||||
|
|
@ -137,26 +133,6 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
return applicationContext;
|
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
|
* Get the {@link ApplicationContext application context} for this test
|
||||||
* context, possibly cached.
|
* context, possibly cached.
|
||||||
|
|
@ -165,6 +141,7 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
* application context
|
* application context
|
||||||
*/
|
*/
|
||||||
public ApplicationContext getApplicationContext() {
|
public ApplicationContext getApplicationContext() {
|
||||||
|
String contextKey = mergedContextConfiguration.getContextKey();
|
||||||
synchronized (contextCache) {
|
synchronized (contextCache) {
|
||||||
ApplicationContext context = contextCache.get(contextKey);
|
ApplicationContext context = contextCache.get(contextKey);
|
||||||
if (context == null) {
|
if (context == null) {
|
||||||
|
|
@ -239,7 +216,9 @@ public class TestContext extends AttributeAccessorSupport {
|
||||||
* replacing a bean definition).
|
* replacing a bean definition).
|
||||||
*/
|
*/
|
||||||
public void markApplicationContextDirty() {
|
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.context.ApplicationContext;
|
||||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||||
|
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||||
import org.springframework.test.context.ContextLoader;
|
import org.springframework.test.context.ContextLoader;
|
||||||
import org.springframework.test.context.ResourceTypeAwareContextLoader;
|
|
||||||
import org.springframework.test.context.SmartContextLoader;
|
import org.springframework.test.context.SmartContextLoader;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
|
|
@ -39,7 +39,17 @@ import org.springframework.util.StringUtils;
|
||||||
* @see #generateDefaultLocations
|
* @see #generateDefaultLocations
|
||||||
* @see #modifyLocations
|
* @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
|
* 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();
|
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.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
import org.springframework.test.context.MergedContextConfiguration;
|
import org.springframework.test.context.MergedContextConfiguration;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.test.context.SmartContextLoader;
|
||||||
import org.springframework.util.StringUtils;
|
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()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(String.format("Loading ApplicationContext for merged context configuration [%s].",
|
logger.debug(String.format("Loading ApplicationContext for merged context configuration [%s].",
|
||||||
mergedContextConfiguration));
|
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();
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
context.getEnvironment().setActiveProfiles(mergedContextConfiguration.getActiveProfiles());
|
context.getEnvironment().setActiveProfiles(mergedContextConfiguration.getActiveProfiles());
|
||||||
prepareContext(context);
|
prepareContext(context);
|
||||||
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
||||||
loadBeanDefinitions(context, locations);
|
loadBeanDefinitions(context, mergedContextConfiguration);
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||||
customizeContext(context);
|
customizeContext(context);
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
@ -84,7 +79,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* prepare the context.</li>
|
* prepare the context.</li>
|
||||||
* <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to
|
* <li>Calls {@link #customizeBeanFactory(DefaultListableBeanFactory)} to
|
||||||
* allow for customizing the context's <code>DefaultListableBeanFactory</code>.</li>
|
* 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>
|
* to populate the context from the specified config locations.</li>
|
||||||
* <li>Delegates to {@link AnnotationConfigUtils} for
|
* <li>Delegates to {@link AnnotationConfigUtils} for
|
||||||
* {@link AnnotationConfigUtils#registerAnnotationConfigProcessors registering}
|
* {@link AnnotationConfigUtils#registerAnnotationConfigProcessors registering}
|
||||||
|
|
@ -106,7 +101,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
GenericApplicationContext context = new GenericApplicationContext();
|
GenericApplicationContext context = new GenericApplicationContext();
|
||||||
prepareContext(context);
|
prepareContext(context);
|
||||||
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
customizeBeanFactory(context.getDefaultListableBeanFactory());
|
||||||
loadBeanDefinitions(context, locations);
|
createBeanDefinitionReader(context).loadBeanDefinitions(locations);
|
||||||
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
AnnotationConfigUtils.registerAnnotationConfigProcessors(context);
|
||||||
customizeContext(context);
|
customizeContext(context);
|
||||||
context.refresh();
|
context.refresh();
|
||||||
|
|
@ -154,12 +149,13 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||||
* and override this method to provide a custom strategy for loading or
|
* and override this method to provide a custom strategy for loading or
|
||||||
* registering bean definitions.
|
* registering bean definitions.
|
||||||
* @param context the context into which the bean definitions should be loaded
|
* @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
|
* @since 3.1
|
||||||
* @see #loadContext
|
* @see #loadContext
|
||||||
*/
|
*/
|
||||||
protected void loadBeanDefinitions(GenericApplicationContext context, String... locations) {
|
protected void loadBeanDefinitions(GenericApplicationContext context,
|
||||||
createBeanDefinitionReader(context).loadBeanDefinitions(locations);
|
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}.
|
* loading bean definitions into the supplied {@link GenericApplicationContext context}.
|
||||||
* @param context the context for which the BeanDefinitionReader should be created
|
* @param context the context for which the BeanDefinitionReader should be created
|
||||||
* @return a BeanDefinitionReader for the supplied context
|
* @return a BeanDefinitionReader for the supplied context
|
||||||
* @see #loadBeanDefinitions
|
* @see #loadContext(String...)
|
||||||
* @see BeanDefinitionReader
|
* @see BeanDefinitionReader
|
||||||
*/
|
*/
|
||||||
protected abstract BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context);
|
protected abstract BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context);
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,16 @@
|
||||||
|
|
||||||
package org.springframework.test.context.support;
|
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.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
import org.springframework.beans.factory.support.BeanDefinitionReader;
|
||||||
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
|
||||||
import org.springframework.context.support.GenericApplicationContext;
|
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.Assert;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
|
@ -30,13 +34,6 @@ import org.springframework.util.ObjectUtils;
|
||||||
* registers bean definitions from
|
* registers bean definitions from
|
||||||
* {@link org.springframework.context.annotation.Configuration configuration classes}.
|
* {@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
|
* @author Sam Brannen
|
||||||
* @since 3.1
|
* @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}
|
* Registers {@link org.springframework.context.annotation.Configuration configuration classes}
|
||||||
* in the supplied {@link GenericApplicationContext context} from the specified
|
* in the supplied {@link GenericApplicationContext context} from the specified
|
||||||
* class names.
|
* class names.
|
||||||
|
|
@ -64,21 +76,9 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
||||||
* @throws IllegalArgumentException if a supplied class name does not represent a class
|
* @throws IllegalArgumentException if a supplied class name does not represent a class
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void loadBeanDefinitions(GenericApplicationContext context, String... classNames) {
|
protected void loadBeanDefinitions(GenericApplicationContext context,
|
||||||
|
MergedContextConfiguration mergedContextConfiguration) {
|
||||||
Class<?>[] configClasses = new Class<?>[classNames.length];
|
Class<?>[] configClasses = mergedContextConfiguration.getClasses();
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Registering configuration classes: " + ObjectUtils.nullSafeToString(configClasses));
|
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 boolean isGenerateDefaultClasses() {
|
||||||
protected BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {
|
return true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -133,17 +103,64 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
||||||
*
|
*
|
||||||
* @see #generateDefaultLocations(Class)
|
* @see #generateDefaultLocations(Class)
|
||||||
*/
|
*/
|
||||||
@Override
|
protected String getConfigurationClassNameSuffix() {
|
||||||
protected String getResourceSuffix() {
|
|
||||||
return "$ContextConfiguration";
|
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
|
@Override
|
||||||
public final ResourceType getResourceType() {
|
protected BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {
|
||||||
return ResourceType.CLASSES;
|
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 {
|
public class ContextLoaderUtilsTests {
|
||||||
|
|
||||||
|
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[] {};
|
||||||
private static final String[] EMPTY_STRING_ARRAY = new String[] {};
|
private static final String[] EMPTY_STRING_ARRAY = new String[] {};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,7 +49,7 @@ public class ContextLoaderUtilsTests {
|
||||||
assertArrayEquals(expectedLocations, attributes.getLocations());
|
assertArrayEquals(expectedLocations, attributes.getLocations());
|
||||||
assertArrayEquals(expectedClasses, attributes.getClasses());
|
assertArrayEquals(expectedClasses, attributes.getClasses());
|
||||||
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
|
assertEquals(expectedInheritLocations, attributes.isInheritLocations());
|
||||||
assertEquals(expectedContextLoaderClass, attributes.getContextLoader());
|
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertFooAttributes(ContextConfigurationAttributes attributes) {
|
private void assertFooAttributes(ContextConfigurationAttributes attributes) {
|
||||||
|
|
@ -62,12 +63,14 @@ public class ContextLoaderUtilsTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertMergedContextConfiguration(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass,
|
private void assertMergedContextConfiguration(MergedContextConfiguration mergedConfig, Class<?> expectedTestClass,
|
||||||
String[] expectedLocations, Class<? extends ContextLoader> expectedContextLoaderClass) {
|
String[] expectedLocations, Class<?>[] expectedClasses,
|
||||||
|
Class<? extends ContextLoader> expectedContextLoaderClass) {
|
||||||
assertNotNull(mergedConfig);
|
assertNotNull(mergedConfig);
|
||||||
assertEquals(expectedTestClass, mergedConfig.getTestClass());
|
assertEquals(expectedTestClass, mergedConfig.getTestClass());
|
||||||
assertNotNull(mergedConfig.getLocations());
|
assertNotNull(mergedConfig.getLocations());
|
||||||
assertArrayEquals(expectedLocations, mergedConfig.getLocations());
|
assertArrayEquals(expectedLocations, mergedConfig.getLocations());
|
||||||
assertNotNull(mergedConfig.getClasses());
|
assertNotNull(mergedConfig.getClasses());
|
||||||
|
assertArrayEquals(expectedClasses, mergedConfig.getClasses());
|
||||||
assertNotNull(mergedConfig.getActiveProfiles());
|
assertNotNull(mergedConfig.getActiveProfiles());
|
||||||
assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass());
|
assertEquals(expectedContextLoaderClass, mergedConfig.getContextLoader().getClass());
|
||||||
}
|
}
|
||||||
|
|
@ -82,7 +85,7 @@ public class ContextLoaderUtilsTests {
|
||||||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(BareAnnotations.class);
|
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(BareAnnotations.class);
|
||||||
assertNotNull(attributesList);
|
assertNotNull(attributesList);
|
||||||
assertEquals(1, attributesList.size());
|
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);
|
ContextLoader.class, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +120,7 @@ public class ContextLoaderUtilsTests {
|
||||||
mergedConfig,
|
mergedConfig,
|
||||||
testClass,
|
testClass,
|
||||||
new String[] { "classpath:/org/springframework/test/context/ContextLoaderUtilsTests$BareAnnotations-context.xml" },
|
new String[] { "classpath:/org/springframework/test/context/ContextLoaderUtilsTests$BareAnnotations-context.xml" },
|
||||||
GenericXmlContextLoader.class);
|
EMPTY_CLASS_ARRAY, GenericXmlContextLoader.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -126,31 +129,28 @@ public class ContextLoaderUtilsTests {
|
||||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||||
|
|
||||||
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
||||||
GenericXmlContextLoader.class);
|
new Class<?>[] { FooConfig.class }, GenericXmlContextLoader.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void buildMergedContextConfigurationWithLocalAnnotationAndOverriddenContexLoader() {
|
public void buildMergedContextConfigurationWithLocalAnnotationAndOverriddenContextLoader() {
|
||||||
Class<?> testClass = Foo.class;
|
Class<?> testClass = Foo.class;
|
||||||
Class<? extends ContextLoader> expectedContextLoaderClass = GenericPropertiesContextLoader.class;
|
Class<? extends ContextLoader> expectedContextLoaderClass = GenericPropertiesContextLoader.class;
|
||||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass,
|
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass,
|
||||||
expectedContextLoaderClass.getName());
|
expectedContextLoaderClass.getName());
|
||||||
|
|
||||||
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
||||||
expectedContextLoaderClass);
|
new Class<?>[] { FooConfig.class }, expectedContextLoaderClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void buildMergedContextConfigurationWithLocalAndInheritedAnnotations() {
|
public void buildMergedContextConfigurationWithLocalAndInheritedAnnotations() {
|
||||||
Class<?> testClass = Bar.class;
|
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);
|
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||||
|
assertMergedContextConfiguration(mergedConfig, testClass, expectedLocations, expectedClasses,
|
||||||
// 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,
|
|
||||||
AnnotationConfigContextLoader.class);
|
AnnotationConfigContextLoader.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for verifying proper behavior of the {@link ContextCache} in
|
* 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
|
* @author Sam Brannen
|
||||||
* @since 3.1
|
* @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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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.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.BeanOverridingDefaultConfigClassesInheritedTests;
|
||||||
|
import org.springframework.test.context.junit4.annotation.BeanOverridingExplicitConfigClassesInheritedTests;
|
||||||
import org.springframework.test.context.junit4.annotation.DefaultConfigClassesBaseTests;
|
import org.springframework.test.context.junit4.annotation.DefaultConfigClassesBaseTests;
|
||||||
import org.springframework.test.context.junit4.annotation.DefaultConfigClassesInheritedTests;
|
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.orm.HibernateSessionFlushingTests;
|
||||||
import org.springframework.test.context.junit4.profile.annotation.DefaultProfileAnnotationConfigTests;
|
import org.springframework.test.context.junit4.profile.annotation.DefaultProfileAnnotationConfigTests;
|
||||||
import org.springframework.test.context.junit4.profile.annotation.DevProfileAnnotationConfigTests;
|
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;
|
import org.springframework.test.context.junit4.profile.xml.DevProfileXmlConfigTests;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* JUnit test suite for tests involving {@link SpringJUnit4ClassRunner} and the
|
||||||
* JUnit 4 based test suite for tests involving {@link SpringJUnit4ClassRunner}
|
* <em>Spring TestContext Framework</em>.
|
||||||
* and the <em>Spring TestContext Framework</em>.
|
*
|
||||||
* </p>
|
* <p>This test suite serves a dual purpose of verifying that tests run with
|
||||||
* <p>
|
* {@link SpringJUnit4ClassRunner} can be used in conjunction with JUnit's
|
||||||
* This test suite serves a dual purpose of verifying that tests run with
|
|
||||||
* {@link SpringJUnit4ClassRunner} can be used in conjunction with JUnit 4's
|
|
||||||
* {@link Suite} runner.
|
* {@link Suite} runner.
|
||||||
* </p>
|
*
|
||||||
* <p>
|
* <p>Note that tests included in this suite will be executed at least twice if
|
||||||
* Note that tests included in this suite will be executed at least twice if run
|
* run from an automated build process, test runner, etc. that is configured to
|
||||||
* from an automated build process, test runner, etc. that is configured to run
|
* run tests based on a "*Tests.class" pattern match.
|
||||||
* tests based on a "*Tests.class" pattern match.
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 2.5
|
* @since 2.5
|
||||||
|
|
@ -58,6 +57,9 @@ StandardJUnit4FeaturesTests.class,//
|
||||||
AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,//
|
AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.class,//
|
||||||
DefaultConfigClassesBaseTests.class,//
|
DefaultConfigClassesBaseTests.class,//
|
||||||
DefaultConfigClassesInheritedTests.class,//
|
DefaultConfigClassesInheritedTests.class,//
|
||||||
|
BeanOverridingDefaultConfigClassesInheritedTests.class,//
|
||||||
|
ExplicitConfigClassesInheritedTests.class,//
|
||||||
|
BeanOverridingExplicitConfigClassesInheritedTests.class,//
|
||||||
DefaultProfileAnnotationConfigTests.class,//
|
DefaultProfileAnnotationConfigTests.class,//
|
||||||
DevProfileAnnotationConfigTests.class, //
|
DevProfileAnnotationConfigTests.class, //
|
||||||
DefaultProfileXmlConfigTests.class,//
|
DefaultProfileXmlConfigTests.class,//
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue