提交 40cff5e3 编写于 作者: J Juergen Hoeller

Polishing

上级 ee35b5ed
......@@ -91,10 +91,8 @@ public @interface ContextConfiguration {
/**
* Alias for {@link #locations}.
*
* <p>This attribute may <strong>not</strong> be used in conjunction with
* {@link #locations}, but it may be used instead of {@link #locations}.
*
* @since 3.0
* @see #inheritLocations
*/
......@@ -104,7 +102,6 @@ public @interface ContextConfiguration {
/**
* The resource locations to use for loading an
* {@link org.springframework.context.ApplicationContext ApplicationContext}.
*
* <p>Check out the Javadoc for
* {@link org.springframework.test.context.support.AbstractContextLoader#modifyLocations
* AbstractContextLoader.modifyLocations()} for details on how a location
......@@ -113,7 +110,6 @@ public @interface ContextConfiguration {
* {@link org.springframework.test.context.support.AbstractContextLoader#generateDefaultLocations
* AbstractContextLoader.generateDefaultLocations()} for details on the
* default locations that are going to be used if none are specified.
*
* <p>Note that the aforementioned default rules only apply for a standard
* {@link org.springframework.test.context.support.AbstractContextLoader
* AbstractContextLoader} subclass such as
......@@ -122,10 +118,8 @@ public @interface ContextConfiguration {
* which are the effective default implementations used at runtime if
* {@code locations} are configured. See the documentation for {@link #loader}
* for further details regarding default loaders.
*
* <p>This attribute may <strong>not</strong> be used in conjunction with
* {@link #value}, but it may be used instead of {@link #value}.
*
* @since 2.5
* @see #inheritLocations
*/
......@@ -135,14 +129,12 @@ public @interface ContextConfiguration {
/**
* The <em>annotated classes</em> to use for loading an
* {@link org.springframework.context.ApplicationContext ApplicationContext}.
*
* <p>Check out the Javadoc for
* <p>Check out the javadoc for
* {@link org.springframework.test.context.support.AnnotationConfigContextLoader#detectDefaultConfigurationClasses
* AnnotationConfigContextLoader.detectDefaultConfigurationClasses()} for details
* on how default configuration classes will be detected if no
* <em>annotated classes</em> are specified. See the documentation for
* {@link #loader} for further details regarding default loaders.
*
* @since 3.1
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.test.context.support.AnnotationConfigContextLoader
......@@ -153,16 +145,13 @@ public @interface ContextConfiguration {
/**
* The application context <em>initializer classes</em> to use for initializing
* a {@link ConfigurableApplicationContext}.
*
* <p>The concrete {@code ConfigurableApplicationContext} type supported by each
* declared initializer must be compatible with the type of {@code ApplicationContext}
* created by the {@link SmartContextLoader} in use.
*
* <p>{@code SmartContextLoader} implementations typically detect whether
* Spring's {@link org.springframework.core.Ordered Ordered} interface has been
* implemented or if the @{@link org.springframework.core.annotation.Order Order}
* annotation is present and sort instances accordingly prior to invoking them.
*
* @since 3.2
* @see org.springframework.context.ApplicationContextInitializer
* @see org.springframework.context.ConfigurableApplicationContext
......@@ -174,7 +163,6 @@ public @interface ContextConfiguration {
/**
* Whether or not {@link #locations resource locations} or <em>annotated
* classes</em> from test superclasses should be <em>inherited</em>.
*
* <p>The default value is {@code true}. This means that an annotated
* class will <em>inherit</em> the resource locations or annotated classes
* defined by test superclasses. Specifically, the resource locations or
......@@ -182,12 +170,10 @@ public @interface ContextConfiguration {
* resource locations or annotated classes defined by test superclasses.
* Thus, subclasses have the option of <em>extending</em> the list of resource
* locations or annotated classes.
*
* <p>If {@code inheritLocations} is set to {@code false}, the
* resource locations or annotated classes for the annotated class
* will <em>shadow</em> and effectively replace any resource locations
* or annotated classes defined by superclasses.
*
* <p>In the following example that uses path-based resource locations, the
* {@link org.springframework.context.ApplicationContext ApplicationContext}
* for {@code ExtendedTest} will be loaded from
......@@ -206,7 +192,6 @@ public @interface ContextConfiguration {
* // ...
* }
* </pre>
*
* <p>Similarly, in the following example that uses annotated
* classes, the
* {@link org.springframework.context.ApplicationContext ApplicationContext}
......@@ -233,18 +218,15 @@ public @interface ContextConfiguration {
/**
* Whether or not {@linkplain #initializers context initializers} from test
* superclasses should be <em>inherited</em>.
*
* <p>The default value is {@code true}. This means that an annotated
* class will <em>inherit</em> the application context initializers defined
* by test superclasses. Specifically, the initializers for a given test
* class will be added to the set of initializers defined by test
* superclasses. Thus, subclasses have the option of <em>extending</em> the
* set of initializers.
*
* <p>If {@code inheritInitializers} is set to {@code false}, the
* initializers for the annotated class will <em>shadow</em> and effectively
* replace any initializers defined by superclasses.
*
* <p>In the following example, the
* {@link org.springframework.context.ApplicationContext ApplicationContext}
* for {@code ExtendedTest} will be initialized using
......@@ -272,12 +254,10 @@ public @interface ContextConfiguration {
* The type of {@link SmartContextLoader} (or {@link ContextLoader}) to use
* for loading an {@link org.springframework.context.ApplicationContext
* ApplicationContext}.
*
* <p>If not specified, the loader will be inherited from the first superclass
* that is annotated with {@code @ContextConfiguration} and specifies an
* explicit loader. If no class in the hierarchy specifies an explicit
* loader, a default loader will be used instead.
*
* <p>The default concrete implementation chosen at runtime will be either
* {@link org.springframework.test.context.support.DelegatingSmartContextLoader
* DelegatingSmartContextLoader} or
......@@ -293,23 +273,19 @@ public @interface ContextConfiguration {
* {@link org.springframework.test.context.web.GenericXmlWebContextLoader GenericXmlWebContextLoader},
* {@link org.springframework.test.context.web.GenericGroovyXmlWebContextLoader GenericGroovyXmlWebContextLoader}, and
* {@link org.springframework.test.context.web.AnnotationConfigWebContextLoader AnnotationConfigWebContextLoader}.
*
* @since 2.5
*/
Class<? extends ContextLoader> loader() default ContextLoader.class;
/**
* The name of the context hierarchy level represented by this configuration.
*
* <p>If not specified the name will be inferred based on the numerical level
* within all declared contexts within the hierarchy.
*
* <p>This attribute is only applicable when used within a test class hierarchy
* that is configured using {@code @ContextHierarchy}, in which case the name
* can be used for <em>merging</em> or <em>overriding</em> this configuration
* with configuration of the same name in hierarchy levels defined in superclasses.
* See the Javadoc for {@link ContextHierarchy @ContextHierarchy} for details.
*
* @since 3.2.2
*/
String name() default "";
......
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2015 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.
......@@ -148,7 +148,6 @@ public @interface ContextHierarchy {
/**
* A list of {@link ContextConfiguration @ContextConfiguration} instances,
* each of which defines a level in the context hierarchy.
*
* <p>If you need to merge or override the configuration for a given level
* of the context hierarchy within a test class hierarchy, you must explicitly
* name that level by supplying the same value to the {@link ContextConfiguration#name
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2015 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.
......@@ -33,8 +33,7 @@ import org.springframework.context.ApplicationContext;
* The results of {@link #processLocations(Class, String...) processLocations()}
* should then be supplied to {@link #loadContext(String...) loadContext()}.
*
* <p>Concrete implementations must provide a {@code public} no-args
* constructor.
* <p>Concrete implementations must provide a {@code public} no-args constructor.
*
* <p>Spring provides the following out-of-the-box implementations:
* <ul>
......@@ -52,10 +51,8 @@ public interface ContextLoader {
/**
* Processes application context resource locations for a specified class.
*
* <p>Concrete implementations may choose to modify the supplied locations,
* generate new locations, or simply return the supplied locations unchanged.
*
* @param clazz the class with which the locations are associated: used to
* determine how to process the supplied locations
* @param locations the unmodified locations to use for loading the
......@@ -68,10 +65,8 @@ public interface ContextLoader {
* Loads a new {@link ApplicationContext context} based on the supplied
* {@code locations}, configures the context, and finally returns
* the context in fully <em>refreshed</em> state.
*
* <p>Configuration locations are generally considered to be classpath
* resources by default.
*
* <p>Concrete implementations should register annotation configuration
* processors with bean factories of {@link ApplicationContext application
* contexts} loaded by this ContextLoader. Beans will therefore automatically
......@@ -79,13 +74,11 @@ public interface ContextLoader {
* {@link org.springframework.beans.factory.annotation.Autowired @Autowired},
* {@link javax.annotation.Resource @Resource}, and
* {@link javax.inject.Inject @Inject}.
*
* <p>Any ApplicationContext loaded by a ContextLoader <strong>must</strong>
* register a JVM shutdown hook for itself. Unless the context gets closed
* early, all context instances will be automatically closed on JVM
* shutdown. This allows for freeing external resources held by beans within
* the context, e.g. temporary files.
*
* @param locations the resource locations to use to load the application context
* @return a new application context
* @throws Exception if context loading failed
......
......@@ -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 {
* 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 {
* {@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 {
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 {
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 {
* 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 {
* @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 {
// 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 {
* 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 {
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 {
*/
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);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册