|
|
|
@ -56,63 +56,10 @@ abstract class ContextLoaderUtils {
@@ -56,63 +56,10 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
/* no-op */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Resolve the list of {@link ContextConfigurationAttributes configuration |
|
|
|
|
* attributes} for the supplied {@link Class class} and its superclasses. |
|
|
|
|
* <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>, configuration attributes defined in the annotated |
|
|
|
|
* class will be appended to the configuration attributes defined in |
|
|
|
|
* superclasses. |
|
|
|
|
* @param clazz the class for which to resolve the configuration attributes (must |
|
|
|
|
* not be <code>null</code>) |
|
|
|
|
* @return the list of configuration attributes for the specified class, |
|
|
|
|
* including configuration attributes from superclasses if appropriate |
|
|
|
|
* (never <code>null</code>) |
|
|
|
|
* @throws IllegalArgumentException if the supplied class is <code>null</code> |
|
|
|
|
* or 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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Resolve the {@link ContextLoader} {@link Class class} to use for the |
|
|
|
|
* supplied {@link Class testClass} and {@link ContextConfigurationAttributes} |
|
|
|
|
* and then instantiate and return that {@code ContextLoader}. |
|
|
|
|
* supplied {@link Class testClass} and then instantiate and return that |
|
|
|
|
* {@code ContextLoader}. |
|
|
|
|
* <p>If the supplied <code>defaultContextLoaderClassName</code> is |
|
|
|
|
* <code>null</code> or <em>empty</em>, the <em>standard</em> |
|
|
|
|
* default context loader class name {@value #DEFAULT_CONTEXT_LOADER_CLASS_NAME} |
|
|
|
@ -120,25 +67,20 @@ abstract class ContextLoaderUtils {
@@ -120,25 +67,20 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
* {@link #resolveContextLoaderClass()}. |
|
|
|
|
* @param testClass the test class for which the {@code ContextLoader} |
|
|
|
|
* should be resolved (must not be <code>null</code>) |
|
|
|
|
* @param configAttributesList the resolved configuration attributes for the |
|
|
|
|
* test class hierarchy |
|
|
|
|
* @param defaultContextLoaderClassName the name of the default |
|
|
|
|
* {@code ContextLoader} class to use (may be <code>null</code>) |
|
|
|
|
* @return the resolved {@code ContextLoader} for the supplied |
|
|
|
|
* <code>testClass</code> (never <code>null</code>) |
|
|
|
|
* @see #resolveContextLoaderClass() |
|
|
|
|
* @see #resolveContextConfigurationAttributes() |
|
|
|
|
*/ |
|
|
|
|
static ContextLoader resolveContextLoader(Class<?> testClass, |
|
|
|
|
List<ContextConfigurationAttributes> configAttributesList, String defaultContextLoaderClassName) { |
|
|
|
|
static ContextLoader resolveContextLoader(Class<?> testClass, String defaultContextLoaderClassName) { |
|
|
|
|
Assert.notNull(testClass, "Test class must not be null"); |
|
|
|
|
Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty"); |
|
|
|
|
|
|
|
|
|
if (!StringUtils.hasText(defaultContextLoaderClassName)) { |
|
|
|
|
defaultContextLoaderClassName = DEFAULT_CONTEXT_LOADER_CLASS_NAME; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass, configAttributesList, |
|
|
|
|
Class<? extends ContextLoader> contextLoaderClass = resolveContextLoaderClass(testClass, |
|
|
|
|
defaultContextLoaderClassName); |
|
|
|
|
|
|
|
|
|
return (ContextLoader) BeanUtils.instantiateClass(contextLoaderClass); |
|
|
|
@ -146,56 +88,61 @@ abstract class ContextLoaderUtils {
@@ -146,56 +88,61 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Resolve the {@link ContextLoader} {@link Class} to use for the supplied |
|
|
|
|
* {@link ContextConfigurationAttributes} list. |
|
|
|
|
* <p>This method will iterate over the supplied configuration attributes |
|
|
|
|
* and execute the following algorithm: |
|
|
|
|
* {@link Class testClass}. |
|
|
|
|
* <ol> |
|
|
|
|
* <li>If {@link ContextConfigurationAttributes#getContextLoaderClass()} |
|
|
|
|
* returns an explicit implementation class, that class will be returned.</li> |
|
|
|
|
* <li>If an explicit {@code ContextLoader} implementation class is not |
|
|
|
|
* specified, the next {@link ContextConfigurationAttributes} instance in |
|
|
|
|
* the supplied list will be processed; go to step #1.</li> |
|
|
|
|
* <li>If no explicit <code>loader</code> class is found after processing |
|
|
|
|
* all {@link ContextConfigurationAttributes} instances, an attempt will be |
|
|
|
|
* made to load and return the class with the supplied |
|
|
|
|
* <code>defaultContextLoaderClassName</code>.</li> |
|
|
|
|
* <li>If the {@link ContextConfiguration#loader() loader} attribute of |
|
|
|
|
* {@link ContextConfiguration @ContextConfiguration} is configured |
|
|
|
|
* with an explicit class, that class will be returned.</li> |
|
|
|
|
* <li>If a <code>loader</code> class is not specified, the class hierarchy |
|
|
|
|
* will be traversed to find a parent class annotated with |
|
|
|
|
* {@code @ContextConfiguration}; go to step #1.</li> |
|
|
|
|
* <li>If no explicit <code>loader</code> class is found after traversing |
|
|
|
|
* the class hierarchy, an attempt will be made to load and return the class |
|
|
|
|
* with the supplied <code>defaultContextLoaderClassName</code>.</li> |
|
|
|
|
* </ol> |
|
|
|
|
* @param testClass the class for which to resolve the {@code ContextLoader} |
|
|
|
|
* class; used solely for logging purposes; must not be <code>null</code> |
|
|
|
|
* @param configAttributesList the resolved configuration attributes for the |
|
|
|
|
* test class hierarchy; must not be <code>null</code> or empty |
|
|
|
|
* class; must not be <code>null</code> |
|
|
|
|
* @param defaultContextLoaderClassName the name of the default |
|
|
|
|
* {@code ContextLoader} class to use; must not be <code>null</code> or empty |
|
|
|
|
* @return the {@code ContextLoader} class to use for the specified class |
|
|
|
|
* (never <code>null</code>) |
|
|
|
|
* @return the {@code ContextLoader} class to use for the supplied test class |
|
|
|
|
* @throws IllegalArgumentException if {@code @ContextConfiguration} is not |
|
|
|
|
* <em>present</em> on the supplied test class |
|
|
|
|
* @see #resolveContextLoader() |
|
|
|
|
* @see #resolveContextConfigurationAttributes() |
|
|
|
|
* <em>present</em> on the supplied test class |
|
|
|
|
* @throws IllegalStateException if the default {@code ContextLoader} class |
|
|
|
|
* could not be loaded |
|
|
|
|
*/ |
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
static Class<? extends ContextLoader> resolveContextLoaderClass(Class<?> testClass, |
|
|
|
|
List<ContextConfigurationAttributes> configAttributesList, String defaultContextLoaderClassName) { |
|
|
|
|
String defaultContextLoaderClassName) { |
|
|
|
|
Assert.notNull(testClass, "Class must not be null"); |
|
|
|
|
Assert.notEmpty(configAttributesList, "ContextConfigurationAttributes list must not be null or empty"); |
|
|
|
|
Assert.hasText(defaultContextLoaderClassName, "Default ContextLoader class name must not be null or empty"); |
|
|
|
|
|
|
|
|
|
for (ContextConfigurationAttributes configAttributes : configAttributesList) { |
|
|
|
|
Class<ContextConfiguration> annotationType = ContextConfiguration.class; |
|
|
|
|
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, testClass); |
|
|
|
|
Assert.notNull(declaringClass, String.format( |
|
|
|
|
"Could not find an 'annotation declaring class' for annotation type [%s] and test class [%s]", |
|
|
|
|
annotationType, testClass)); |
|
|
|
|
|
|
|
|
|
while (declaringClass != null) { |
|
|
|
|
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType); |
|
|
|
|
|
|
|
|
|
if (logger.isTraceEnabled()) { |
|
|
|
|
logger.trace(String.format( |
|
|
|
|
"Processing ContextLoader for context configuration attributes [%s] and test class [%s]", |
|
|
|
|
configAttributes, testClass)); |
|
|
|
|
"Processing ContextLoader for @ContextConfiguration [%s] and declaring class [%s]", |
|
|
|
|
contextConfiguration, declaringClass)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Class<? extends ContextLoader> contextLoaderClass = configAttributes.getContextLoaderClass(); |
|
|
|
|
Class<? extends ContextLoader> contextLoaderClass = contextConfiguration.loader(); |
|
|
|
|
if (!ContextLoader.class.equals(contextLoaderClass)) { |
|
|
|
|
if (logger.isDebugEnabled()) { |
|
|
|
|
logger.debug(String.format( |
|
|
|
|
"Found explicit ContextLoader class [%s] for context configuration attributes [%s] and test class [%s]", |
|
|
|
|
contextLoaderClass, configAttributes, testClass)); |
|
|
|
|
"Found explicit ContextLoader class [%s] for @ContextConfiguration [%s] and declaring class [%s]", |
|
|
|
|
contextLoaderClass, contextConfiguration, declaringClass)); |
|
|
|
|
} |
|
|
|
|
return contextLoaderClass; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, |
|
|
|
|
declaringClass.getSuperclass()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
@ -213,6 +160,58 @@ abstract class ContextLoaderUtils {
@@ -213,6 +160,58 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Resolve the list of {@link ContextConfigurationAttributes configuration |
|
|
|
|
* attributes} for the supplied {@link Class class} and its superclasses. |
|
|
|
|
* <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>, configuration attributes defined in the annotated |
|
|
|
|
* class will be appended to the configuration attributes defined in |
|
|
|
|
* superclasses. |
|
|
|
|
* @param clazz the class for which to resolve the configuration attributes (must |
|
|
|
|
* not be <code>null</code>) |
|
|
|
|
* @return the list of configuration attributes for the specified class, |
|
|
|
|
* including configuration attributes from superclasses if appropriate |
|
|
|
|
* (never <code>null</code>) |
|
|
|
|
* @throws IllegalArgumentException if the supplied class is <code>null</code> or |
|
|
|
|
* if {@code @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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Resolve <em>active bean definition profiles</em> for the supplied {@link Class}. |
|
|
|
|
* <p>Note that the {@link ActiveProfiles#inheritProfiles inheritProfiles} |
|
|
|
@ -286,8 +285,8 @@ abstract class ContextLoaderUtils {
@@ -286,8 +285,8 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
* @param defaultContextLoaderClassName the name of the default |
|
|
|
|
* {@code ContextLoader} class to use (may be <code>null</code>) |
|
|
|
|
* @return the merged context configuration |
|
|
|
|
* @see #resolveContextConfigurationAttributes() |
|
|
|
|
* @see #resolveContextLoader() |
|
|
|
|
* @see #resolveContextConfigurationAttributes() |
|
|
|
|
* @see SmartContextLoader#processContextConfiguration() |
|
|
|
|
* @see ContextLoader#processLocations() |
|
|
|
|
* @see #resolveActiveProfiles() |
|
|
|
@ -296,16 +295,8 @@ abstract class ContextLoaderUtils {
@@ -296,16 +295,8 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass, |
|
|
|
|
String defaultContextLoaderClassName) { |
|
|
|
|
|
|
|
|
|
List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass); |
|
|
|
|
|
|
|
|
|
ContextLoader contextLoader = resolveContextLoader(testClass, configAttributesList, |
|
|
|
|
defaultContextLoaderClassName); |
|
|
|
|
|
|
|
|
|
// Algorithm:
|
|
|
|
|
// - iterate over config attributes
|
|
|
|
|
// -- let loader process locations
|
|
|
|
|
// -- let loader process classes, if it's a SmartContextLoader
|
|
|
|
|
|
|
|
|
|
final ContextLoader contextLoader = resolveContextLoader(testClass, defaultContextLoaderClassName); |
|
|
|
|
final List<ContextConfigurationAttributes> configAttributesList = resolveContextConfigurationAttributes(testClass); |
|
|
|
|
final List<String> locationsList = new ArrayList<String>(); |
|
|
|
|
final List<Class<?>> classesList = new ArrayList<Class<?>>(); |
|
|
|
|
|
|
|
|
|