|
|
|
@ -57,17 +57,12 @@ abstract class ContextLoaderUtils {
@@ -57,17 +57,12 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
private static final Log logger = LogFactory.getLog(ContextLoaderUtils.class); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ContextLoaderUtils() { |
|
|
|
|
/* no-op */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Resolve the list of lists of {@linkplain ContextConfigurationAttributes context |
|
|
|
|
* configuration attributes} for the supplied {@linkplain Class test class} and its |
|
|
|
|
* superclasses, taking into account context hierarchies declared via |
|
|
|
|
* {@link ContextHierarchy @ContextHierarchy} and |
|
|
|
|
* {@link ContextConfiguration @ContextConfiguration}. |
|
|
|
|
* |
|
|
|
|
* <p>The outer list represents a top-down ordering of context configuration |
|
|
|
|
* attributes, where each element in the list represents the context configuration |
|
|
|
|
* declared on a given test class in the class hierarchy. Each nested list |
|
|
|
@ -77,13 +72,11 @@ abstract class ContextLoaderUtils {
@@ -77,13 +72,11 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
* single {@code @ContextHierarchy} instance on the particular class. |
|
|
|
|
* Furthermore, each nested list maintains the order in which |
|
|
|
|
* {@code @ContextConfiguration} instances are declared. |
|
|
|
|
* |
|
|
|
|
* <p>Note that the {@link ContextConfiguration#inheritLocations inheritLocations} and |
|
|
|
|
* {@link ContextConfiguration#inheritInitializers() inheritInitializers} flags of |
|
|
|
|
* {@link ContextConfiguration @ContextConfiguration} will <strong>not</strong> |
|
|
|
|
* be taken into consideration. If these flags need to be honored, that must be |
|
|
|
|
* handled manually when traversing the nested lists returned by this method. |
|
|
|
|
* |
|
|
|
|
* @param testClass the class for which to resolve the context hierarchy attributes |
|
|
|
|
* (must not be {@code null}) |
|
|
|
|
* @return the list of lists of configuration attributes for the specified class; |
|
|
|
@ -95,7 +88,6 @@ abstract class ContextLoaderUtils {
@@ -95,7 +88,6 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
* {@code @ContextHierarchy} as top-level annotations. |
|
|
|
|
* @throws IllegalStateException if no class in the class hierarchy declares |
|
|
|
|
* {@code @ContextHierarchy}. |
|
|
|
|
* |
|
|
|
|
* @since 3.2.2 |
|
|
|
|
* @see #buildContextHierarchyMap(Class) |
|
|
|
|
* @see #resolveContextConfigurationAttributes(Class) |
|
|
|
@ -109,23 +101,25 @@ abstract class ContextLoaderUtils {
@@ -109,23 +101,25 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
final Class<ContextHierarchy> contextHierarchyType = ContextHierarchy.class; |
|
|
|
|
final List<List<ContextConfigurationAttributes>> hierarchyAttributes = new ArrayList<List<ContextConfigurationAttributes>>(); |
|
|
|
|
|
|
|
|
|
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(testClass, contextConfigType, |
|
|
|
|
contextHierarchyType); |
|
|
|
|
Assert.notNull(descriptor, String.format( |
|
|
|
|
"Could not find an 'annotation declaring class' for annotation type [%s] or [%s] and test class [%s]", |
|
|
|
|
contextConfigType.getName(), contextHierarchyType.getName(), testClass.getName())); |
|
|
|
|
UntypedAnnotationDescriptor desc = |
|
|
|
|
findAnnotationDescriptorForTypes(testClass, contextConfigType, contextHierarchyType); |
|
|
|
|
if (desc == null) { |
|
|
|
|
throw new IllegalArgumentException(String.format( |
|
|
|
|
"Could not find an 'annotation declaring class' for annotation type [%s] or [%s] and test class [%s]", |
|
|
|
|
contextConfigType.getName(), contextHierarchyType.getName(), testClass.getName())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (descriptor != null) { |
|
|
|
|
Class<?> rootDeclaringClass = descriptor.getRootDeclaringClass(); |
|
|
|
|
Class<?> declaringClass = descriptor.getDeclaringClass(); |
|
|
|
|
while (desc != null) { |
|
|
|
|
Class<?> rootDeclaringClass = desc.getRootDeclaringClass(); |
|
|
|
|
Class<?> declaringClass = desc.getDeclaringClass(); |
|
|
|
|
|
|
|
|
|
boolean contextConfigDeclaredLocally = isAnnotationDeclaredLocally(contextConfigType, declaringClass); |
|
|
|
|
boolean contextHierarchyDeclaredLocally = isAnnotationDeclaredLocally(contextHierarchyType, declaringClass); |
|
|
|
|
|
|
|
|
|
if (contextConfigDeclaredLocally && contextHierarchyDeclaredLocally) { |
|
|
|
|
String msg = String.format("Class [%s] has been configured with both @ContextConfiguration " |
|
|
|
|
+ "and @ContextHierarchy. Only one of these annotations may be declared on a test class " |
|
|
|
|
+ "or composed annotation.", declaringClass.getName()); |
|
|
|
|
String msg = String.format("Class [%s] has been configured with both @ContextConfiguration " + |
|
|
|
|
"and @ContextHierarchy. Only one of these annotations may be declared on a test class " + |
|
|
|
|
"or composed annotation.", declaringClass.getName()); |
|
|
|
|
logger.error(msg); |
|
|
|
|
throw new IllegalStateException(msg); |
|
|
|
|
} |
|
|
|
@ -134,30 +128,28 @@ abstract class ContextLoaderUtils {
@@ -134,30 +128,28 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
|
|
|
|
|
if (contextConfigDeclaredLocally) { |
|
|
|
|
ContextConfiguration contextConfiguration = AnnotationUtils.synthesizeAnnotation( |
|
|
|
|
descriptor.getAnnotationAttributes(), ContextConfiguration.class, |
|
|
|
|
descriptor.getRootDeclaringClass()); |
|
|
|
|
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, rootDeclaringClass, |
|
|
|
|
configAttributesList); |
|
|
|
|
desc.getAnnotationAttributes(), ContextConfiguration.class, desc.getRootDeclaringClass()); |
|
|
|
|
convertContextConfigToConfigAttributesAndAddToList( |
|
|
|
|
contextConfiguration, rootDeclaringClass, configAttributesList); |
|
|
|
|
} |
|
|
|
|
else if (contextHierarchyDeclaredLocally) { |
|
|
|
|
ContextHierarchy contextHierarchy = getAnnotation(declaringClass, contextHierarchyType); |
|
|
|
|
for (ContextConfiguration contextConfiguration : contextHierarchy.value()) { |
|
|
|
|
convertContextConfigToConfigAttributesAndAddToList(contextConfiguration, rootDeclaringClass, |
|
|
|
|
configAttributesList); |
|
|
|
|
convertContextConfigToConfigAttributesAndAddToList( |
|
|
|
|
contextConfiguration, rootDeclaringClass, configAttributesList); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
// This should theoretically never happen...
|
|
|
|
|
String msg = String.format("Test class [%s] has been configured with neither @ContextConfiguration " |
|
|
|
|
+ "nor @ContextHierarchy as a class-level annotation.", rootDeclaringClass.getName()); |
|
|
|
|
String msg = String.format("Test class [%s] has been configured with neither @ContextConfiguration " + |
|
|
|
|
"nor @ContextHierarchy as a class-level annotation.", rootDeclaringClass.getName()); |
|
|
|
|
logger.error(msg); |
|
|
|
|
throw new IllegalStateException(msg); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
hierarchyAttributes.add(0, configAttributesList); |
|
|
|
|
|
|
|
|
|
descriptor = findAnnotationDescriptorForTypes(rootDeclaringClass.getSuperclass(), contextConfigType, |
|
|
|
|
contextHierarchyType); |
|
|
|
|
desc = findAnnotationDescriptorForTypes( |
|
|
|
|
rootDeclaringClass.getSuperclass(), contextConfigType, contextHierarchyType); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return hierarchyAttributes; |
|
|
|
@ -168,18 +160,15 @@ abstract class ContextLoaderUtils {
@@ -168,18 +160,15 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
* test class} and its superclasses, taking into account context hierarchies |
|
|
|
|
* declared via {@link ContextHierarchy @ContextHierarchy} and |
|
|
|
|
* {@link ContextConfiguration @ContextConfiguration}. |
|
|
|
|
* |
|
|
|
|
* <p>Each value in the map represents the consolidated list of {@linkplain |
|
|
|
|
* ContextConfigurationAttributes context configuration attributes} for a |
|
|
|
|
* given level in the context hierarchy (potentially across the test class |
|
|
|
|
* hierarchy), keyed by the {@link ContextConfiguration#name() name} of the |
|
|
|
|
* context hierarchy level. |
|
|
|
|
* |
|
|
|
|
* <p>If a given level in the context hierarchy does not have an explicit |
|
|
|
|
* name (i.e., configured via {@link ContextConfiguration#name}), a name will |
|
|
|
|
* be generated for that hierarchy level by appending the numerical level to |
|
|
|
|
* the {@link #GENERATED_CONTEXT_HIERARCHY_LEVEL_PREFIX}. |
|
|
|
|
* |
|
|
|
|
* @param testClass the class for which to resolve the context hierarchy map |
|
|
|
|
* (must not be {@code null}) |
|
|
|
|
* @return a map of context configuration attributes for the context hierarchy, |
|
|
|
@ -187,7 +176,6 @@ abstract class ContextLoaderUtils {
@@ -187,7 +176,6 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
* @throws IllegalArgumentException if the lists of context configuration |
|
|
|
|
* attributes for each level in the {@code @ContextHierarchy} do not define |
|
|
|
|
* unique context configuration within the overall hierarchy. |
|
|
|
|
* |
|
|
|
|
* @since 3.2.2 |
|
|
|
|
* @see #resolveContextHierarchyAttributes(Class) |
|
|
|
|
*/ |
|
|
|
@ -217,9 +205,9 @@ abstract class ContextLoaderUtils {
@@ -217,9 +205,9 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
// Check for uniqueness
|
|
|
|
|
Set<List<ContextConfigurationAttributes>> set = new HashSet<List<ContextConfigurationAttributes>>(map.values()); |
|
|
|
|
if (set.size() != map.size()) { |
|
|
|
|
String msg = String.format("The @ContextConfiguration elements configured via " |
|
|
|
|
+ "@ContextHierarchy in test class [%s] and its superclasses must " |
|
|
|
|
+ "define unique contexts per hierarchy level.", testClass.getName()); |
|
|
|
|
String msg = String.format("The @ContextConfiguration elements configured via @ContextHierarchy in " + |
|
|
|
|
"test class [%s] and its superclasses must define unique contexts per hierarchy level.", |
|
|
|
|
testClass.getName()); |
|
|
|
|
logger.error(msg); |
|
|
|
|
throw new IllegalStateException(msg); |
|
|
|
|
} |
|
|
|
@ -231,15 +219,13 @@ abstract class ContextLoaderUtils {
@@ -231,15 +219,13 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
* Resolve the list of {@linkplain ContextConfigurationAttributes context |
|
|
|
|
* configuration attributes} for the supplied {@linkplain Class test class} and its |
|
|
|
|
* superclasses. |
|
|
|
|
* |
|
|
|
|
* <p>Note that the {@link ContextConfiguration#inheritLocations inheritLocations} and |
|
|
|
|
* {@link ContextConfiguration#inheritInitializers() inheritInitializers} flags of |
|
|
|
|
* {@link ContextConfiguration @ContextConfiguration} will <strong>not</strong> |
|
|
|
|
* be taken into consideration. If these flags need to be honored, that must be |
|
|
|
|
* handled manually when traversing the list returned by this method. |
|
|
|
|
* |
|
|
|
|
* @param testClass the class for which to resolve the configuration attributes (must |
|
|
|
|
* not be {@code null}) |
|
|
|
|
* @param testClass the class for which to resolve the configuration attributes |
|
|
|
|
* (must not be {@code null}) |
|
|
|
|
* @return the list of configuration attributes for the specified class, ordered |
|
|
|
|
* <em>bottom-up</em> (i.e., as if we were traversing up the class hierarchy); |
|
|
|
|
* never {@code null} |
|
|
|
@ -249,18 +235,19 @@ abstract class ContextLoaderUtils {
@@ -249,18 +235,19 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
static List<ContextConfigurationAttributes> resolveContextConfigurationAttributes(Class<?> testClass) { |
|
|
|
|
Assert.notNull(testClass, "Class must not be null"); |
|
|
|
|
|
|
|
|
|
final List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>(); |
|
|
|
|
|
|
|
|
|
List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>(); |
|
|
|
|
Class<ContextConfiguration> annotationType = ContextConfiguration.class; |
|
|
|
|
|
|
|
|
|
AnnotationDescriptor<ContextConfiguration> descriptor = findAnnotationDescriptor(testClass, annotationType); |
|
|
|
|
Assert.notNull(descriptor, String.format( |
|
|
|
|
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", |
|
|
|
|
annotationType.getName(), testClass.getName())); |
|
|
|
|
if (descriptor == null) { |
|
|
|
|
throw new IllegalArgumentException(String.format( |
|
|
|
|
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", |
|
|
|
|
annotationType.getName(), testClass.getName())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
while (descriptor != null) { |
|
|
|
|
convertContextConfigToConfigAttributesAndAddToList(descriptor.synthesizeAnnotation(), |
|
|
|
|
descriptor.getRootDeclaringClass(), attributesList); |
|
|
|
|
descriptor.getRootDeclaringClass(), attributesList); |
|
|
|
|
descriptor = findAnnotationDescriptor(descriptor.getRootDeclaringClass().getSuperclass(), annotationType); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -274,13 +261,13 @@ abstract class ContextLoaderUtils {
@@ -274,13 +261,13 @@ abstract class ContextLoaderUtils {
|
|
|
|
|
*/ |
|
|
|
|
private static void convertContextConfigToConfigAttributesAndAddToList(ContextConfiguration contextConfiguration, |
|
|
|
|
Class<?> declaringClass, final List<ContextConfigurationAttributes> attributesList) { |
|
|
|
|
|
|
|
|
|
if (logger.isTraceEnabled()) { |
|
|
|
|
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].", |
|
|
|
|
contextConfiguration, declaringClass.getName())); |
|
|
|
|
contextConfiguration, declaringClass.getName())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(declaringClass, |
|
|
|
|
contextConfiguration); |
|
|
|
|
ContextConfigurationAttributes attributes = |
|
|
|
|
new ContextConfigurationAttributes(declaringClass, contextConfiguration); |
|
|
|
|
if (logger.isTraceEnabled()) { |
|
|
|
|
logger.trace("Resolved context configuration attributes: " + attributes); |
|
|
|
|
} |
|
|
|
|