[SPR-8386] fleshing out JavaDoc for SmartContextLoader and related classes.

This commit is contained in:
Sam Brannen 2011-06-19 22:41:18 +00:00
parent 81d8ce5597
commit 4d27cde6b7
9 changed files with 193 additions and 45 deletions

View File

@ -22,11 +22,15 @@ import org.springframework.core.style.ToStringCreator;
import org.springframework.util.ObjectUtils; import org.springframework.util.ObjectUtils;
/** /**
* TODO [SPR-8386] Document ContextConfigurationAttributes. * <code>ContextConfigurationAttributes</code> encapsulates the context
* configuration attributes declared on a test class via
* {@link ContextConfiguration @ContextConfiguration}.
* *
* @author Sam Brannen * @author Sam Brannen
* @since 3.1 * @since 3.1
* @see ContextConfiguration * @see ContextConfiguration
* @see SmartContextLoader
* @see MergedContextConfiguration
*/ */
public class ContextConfigurationAttributes { public class ContextConfigurationAttributes {
@ -34,17 +38,17 @@ public class ContextConfigurationAttributes {
private final Class<?> declaringClass; private final Class<?> declaringClass;
private final boolean inheritLocations;
private final Class<? extends ContextLoader> contextLoaderClass;
private String[] locations; private String[] locations;
private Class<?>[] classes; private Class<?>[] classes;
private final boolean inheritLocations;
private final Class<? extends ContextLoader> contextLoaderClass;
/** /**
* Resolves resource locations from the {@link ContextConfiguration#locations() locations} * Resolve resource locations from the {@link ContextConfiguration#locations() locations}
* and {@link ContextConfiguration#value() value} attributes of the supplied * and {@link ContextConfiguration#value() value} attributes of the supplied
* {@link ContextConfiguration} annotation. * {@link ContextConfiguration} annotation.
* *
@ -71,7 +75,11 @@ public class ContextConfigurationAttributes {
} }
/** /**
* TODO Document ContextConfigurationAttributes constructor. * Construct a new {@link ContextConfigurationAttributes} instance for the
* supplied {@link ContextConfiguration @ContextConfiguration} annotation and
* the {@link Class test class} that declared it.
* @param declaringClass the test class that declared {@code @ContextConfiguration}
* @param contextConfiguration the annotation from which to retrieve the attributes
*/ */
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(),
@ -79,7 +87,16 @@ public class ContextConfigurationAttributes {
} }
/** /**
* TODO Document ContextConfigurationAttributes constructor. * Construct a new {@link ContextConfigurationAttributes} instance for the
* {@link Class test class} that declared the
* {@link ContextConfiguration @ContextConfiguration} annotation and its
* corresponding attributes.
*
* @param declaringClass the test class that declared {@code @ContextConfiguration}
* @param locations the resource locations declared via {@code @ContextConfiguration}
* @param classes the configuration classes declared via {@code @ContextConfiguration}
* @param inheritLocations the <code>inheritLocations</code> flag declared via {@code @ContextConfiguration}
* @param contextLoaderClass the {@code ContextLoader} class declared via {@code @ContextConfiguration}
*/ */
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes, public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
boolean inheritLocations, Class<? extends ContextLoader> contextLoaderClass) { boolean inheritLocations, Class<? extends ContextLoader> contextLoaderClass) {
@ -91,56 +108,84 @@ public class ContextConfigurationAttributes {
} }
/** /**
* TODO Document getDeclaringClass(). * Get the {@link Class class} that declared the
* {@link ContextConfiguration @ContextConfiguration} annotation.
* @return the declaring class; never <code>null</code>
*/ */
public Class<?> getDeclaringClass() { public Class<?> getDeclaringClass() {
return this.declaringClass; return this.declaringClass;
} }
/** /**
* TODO Document isInheritLocations(). * Get the resource locations that were declared via
*/ * {@link ContextConfiguration @ContextConfiguration}.
public boolean isInheritLocations() { * <p>Note: this is a mutable property. The returned value may therefore
return this.inheritLocations; * represent a <em>processed</em> value that does not match the original value
} * declared via {@link ContextConfiguration @ContextConfiguration}.
* @return the resource locations; potentially <code>null</code> or <em>empty</em>
/** * @see ContextConfiguration#value
* TODO Document getContextLoaderClass(). * @see ContextConfiguration#locations
*/ * @see #setLocations()
public Class<? extends ContextLoader> getContextLoaderClass() {
return this.contextLoaderClass;
}
/**
* TODO Document getLocations().
*/ */
public String[] getLocations() { public String[] getLocations() {
return this.locations; return this.locations;
} }
/** /**
* TODO Document setLocations(). * Set the <em>processed</em> resource locations, effectively overriding the
* original value declared via {@link ContextConfiguration @ContextConfiguration}.
* @see #getLocations()
*/ */
public void setLocations(String[] locations) { public void setLocations(String[] locations) {
this.locations = locations; this.locations = locations;
} }
/** /**
* TODO Document getClasses(). * Get the configuration classes that were declared via
* {@link ContextConfiguration @ContextConfiguration}.
* <p>Note: this is a mutable property. The returned value may therefore
* represent a <em>processed</em> value that does not match the original value
* declared via {@link ContextConfiguration @ContextConfiguration}.
* @return the configuration classes; potentially <code>null</code> or <em>empty</em>
* @see ContextConfiguration#classes
* @see #setClasses()
*/ */
public Class<?>[] getClasses() { public Class<?>[] getClasses() {
return this.classes; return this.classes;
} }
/** /**
* TODO Document setClasses(). * Set the <em>processed</em> configuration classes, effectively overriding the
* original value declared via {@link ContextConfiguration @ContextConfiguration}.
* @see #getClasses()
*/ */
public void setClasses(Class<?>[] classes) { public void setClasses(Class<?>[] classes) {
this.classes = classes; this.classes = classes;
} }
/** /**
* TODO Document overridden toString(). * Get the <code>inheritLocations</code> flag that was declared via
* {@link ContextConfiguration @ContextConfiguration}.
* @return the <code>inheritLocations</code> flag
* @see ContextConfiguration#inheritLocations
*/
public boolean isInheritLocations() {
return this.inheritLocations;
}
/**
* Get the <code>ContextLoader</code> class that was declared via
* {@link ContextConfiguration @ContextConfiguration}.
* @return the <code>ContextLoader</code> class
* @see ContextConfiguration#loader
*/
public Class<? extends ContextLoader> getContextLoaderClass() {
return this.contextLoaderClass;
}
/**
* Provide a String representation of the context configuration attributes
* and declaring class.
*/ */
@Override @Override
public String toString() { public String toString() {

View File

@ -21,6 +21,10 @@ import org.springframework.context.ApplicationContext;
/** /**
* Strategy interface for loading an {@link ApplicationContext application context}. * Strategy interface for loading an {@link ApplicationContext application context}.
* *
* <p><b>Note</b>: as of Spring 3.1, consider implementing {@link SmartContextLoader}
* instead of this interface in order to provide support for configuration classes
* and active bean definition profiles.
*
* <p>Clients of a ContextLoader should call * <p>Clients of a ContextLoader should call
* {@link #processLocations(Class,String...) processLocations()} prior to * {@link #processLocations(Class,String...) processLocations()} prior to
* calling {@link #loadContext(String...) loadContext()} in case the * calling {@link #loadContext(String...) loadContext()} in case the
@ -41,6 +45,7 @@ import org.springframework.context.ApplicationContext;
* @author Sam Brannen * @author Sam Brannen
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 2.5 * @since 2.5
* @see SmartContextLoader
*/ */
public interface ContextLoader { public interface ContextLoader {

View File

@ -100,7 +100,7 @@ abstract class ContextLoaderUtils {
* *
* @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 configAttributesList TODO Document configAttributesList 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>)
* *
@ -141,7 +141,7 @@ abstract class ContextLoaderUtils {
* *
* @param testClass 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 configAttributesList TODO Document configAttributesList 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
* *

View File

@ -31,6 +31,7 @@ import org.springframework.util.StringUtils;
* @since 3.1 * @since 3.1
* @see ContextConfiguration * @see ContextConfiguration
* @see ActiveProfiles * @see ActiveProfiles
* @see ContextConfigurationAttributes
*/ */
public class MergedContextConfiguration { public class MergedContextConfiguration {

View File

@ -19,20 +19,111 @@ package org.springframework.test.context;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
/** /**
* TODO [SPR-8386] Document SmartContextLoader. * <p>Strategy interface for loading an {@link ApplicationContext application context}
* for an integration test managed by the Spring TestContext Framework.
*
* <p>The <code>SmartContextLoader</code> SPI supersedes the {@link ContextLoader}
* SPI introduced in Spring 2.5: <code>SmartContextLoaders</code> can process both
* resource locations and configuration classes. Furthermore, a
* <code>SmartContextLoader</code> can set active bean definition profiles
* in the context that it loads (see {@link MergedContextConfiguration#getActiveProfiles()}
* and {@link #loadContext(MergedContextConfiguration)}).
*
* <p>Clients of a <code>SmartContextLoader</code> should call
* {@link #processContextConfiguration(ContextConfigurationAttributes) processContextConfiguration()}
* prior to calling {@link #loadContext(MergedContextConfiguration) loadContext()}
* in case the <code>SmartContextLoader</code> provides custom support for modifying
* or generating resource locations or configuration classes. The results of
* {@link #processContextConfiguration(ContextConfigurationAttributes) processContextConfiguration()}
* should be merged for all classes in the hierarchy of the root test class and
* then supplied to {@link #loadContext(MergedContextConfiguration) loadContext()}.
* Even though <code>SmartContextLoader</code> extends <code>ContextLoader</code>,
* clients should favor <code>SmartContextLoader</code>-specific methods over those
* defined in <code>ContextLoader</code>, particularly because a
* <code>SmartContextLoader</code> may choose not to support methods defined in
* the <code>ContextLoader</code> SPI.
*
* <p>Concrete implementations must provide a <code>public</code> no-args constructor.
*
* <p>Spring provides the following out-of-the-box implementations:
* <ul>
* <li>{@link org.springframework.test.context.support.GenericXmlContextLoader GenericXmlContextLoader}</li>
* <li>{@link org.springframework.test.context.support.AnnotationConfigContextLoader AnnotationConfigContextLoader}</li>
* <li>{@link org.springframework.test.context.support.GenericPropertiesContextLoader GenericPropertiesContextLoader}</li>
* </ul>
* *
* @author Sam Brannen * @author Sam Brannen
* @since 3.1 * @since 3.1
* @see ContextConfiguration
* @see ActiveProfiles
* @see ContextConfigurationAttributes
* @see MergedContextConfiguration
*/ */
public interface SmartContextLoader extends ContextLoader { public interface SmartContextLoader extends ContextLoader {
/** /**
* TODO Document processContextConfiguration(). * Determines if this <code>SmartContextLoader</code> generates default resource
* locations or
* {@link org.springframework.context.annotation.Configuration configuration classes}
* if the <code>locations</code> or <code>classes</code>
* present in the {@link ContextConfigurationAttributes} provided to
* {@link #processContextConfiguration()} are <code>null</code> or empty.
* <p>Returning a value of <code>true</code> signals not only that this
* <code>SmartContextLoader</code> generates defaults but also that it will
* <em>preemptively</em> verify that a generated default actually exists.
* @return <code>true</code> if this <code>SmartContextLoader</code>
* generates default configuration locations or classes
* @see #processContextConfiguration
*/
boolean generatesDefaults();
/**
* Processes the {@link ContextConfigurationAttributes} for a given test class.
* <p>Concrete implementations may choose to <em>modify</em> the <code>locations</code>
* or <code>classes</code> in the supplied {@link ContextConfigurationAttributes}
* or <em>generate default</em> configuration locations or classes if the
* supplied values are <code>null</code> or empty.
* <p><b>Note</b>: If {@link #generatesDefaults()} returns <code>true</code>,
* this method <b>must</b> <em>preemptively</em> verify that a generated default
* actually exists before setting the corresponding <code>locations</code>
* or <code>classes</code> property in the supplied
* {@link ContextConfigurationAttributes}. Consequently, leaving the
* <code>locations</code> or <code>classes</code> property empty signals that
* this <code>SmartContextLoader</code> was not able to generate defaults.
* @param configAttributes the context configuration attributes to process
* @see #generatesDefaults
*/ */
void processContextConfiguration(ContextConfigurationAttributes configAttributes); void processContextConfiguration(ContextConfigurationAttributes configAttributes);
/** /**
* TODO Document loadContext(). * Loads a new {@link ApplicationContext context} based on the supplied
* {@link MergedContextConfiguration merged context configuration},
* configures the context, and finally returns the context in a fully
* <em>refreshed</em> state.
* <p>Concrete implementations should register annotation configuration
* processors with bean factories of
* {@link ApplicationContext application contexts} loaded by this
* <code>SmartContextLoader</code>. Beans will therefore automatically be
* candidates for annotation-based dependency injection using
* {@link org.springframework.beans.factory.annotation.Autowired @Autowired},
* {@link javax.annotation.Resource @Resource}, and
* {@link javax.inject.Inject @Inject}. In addition, concrete implementations
* should set the active bean definition profiles in the context's
* {@link org.springframework.core.env.Environment Environment}.
* <p>Any <code>ApplicationContext</code> loaded by a
* <code>SmartContextLoader</code> <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 mergedConfig the merged context configuration to use to load the
* application context
* @return a new application context
* @throws Exception if context loading failed
* @see #processContextConfiguration(ContextConfigurationAttributes)
* @see org.springframework.context.annotation.AnnotationConfigUtils#registerAnnotationConfigProcessors()
* @see org.springframework.test.context.MergedContextConfiguration#getActiveProfiles()
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment()
*/ */
ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception; ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception;

View File

@ -41,6 +41,22 @@ import org.springframework.util.StringUtils;
*/ */
public abstract class AbstractContextLoader implements SmartContextLoader { public abstract class AbstractContextLoader implements SmartContextLoader {
// --- SmartContextLoader -----------------------------------------------
/**
* Determine whether or not <em>default</em> resource locations should be
* generated if the <code>locations</code> provided to
* {@link #processLocations(Class,String...) processLocations()} are
* <code>null</code> or empty.
* <p>Can be overridden by subclasses to change the default behavior.
* @return always <code>true</code> by default
*
* @see SmartContextLoader#generatesDefaults
*/
public boolean generatesDefaults() {
return isGenerateDefaultLocations();
}
/** /**
* TODO Document processContextConfiguration(). * TODO Document processContextConfiguration().
*/ */
@ -51,6 +67,8 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
configAttributes.setLocations(processedLocations); configAttributes.setLocations(processedLocations);
} }
// --- ContextLoader -------------------------------------------------------
/** /**
* If the supplied <code>locations</code> are <code>null</code> or * If the supplied <code>locations</code> are <code>null</code> or
* <em>empty</em> and {@link #isGenerateDefaultLocations()} is * <em>empty</em> and {@link #isGenerateDefaultLocations()} is

View File

@ -101,14 +101,6 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class); return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
} }
/**
* TODO Document generatesDefaults().
*/
// TODO Consider defining generatesDefaults() in the SmartContextLoader SPI.
protected boolean generatesDefaults() {
return true;
}
/** /**
* TODO Document generateDefaultConfigurationClasses(). * TODO Document generateDefaultConfigurationClasses().
*/ */

View File

@ -29,8 +29,6 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/** /**
* TODO Document DefaultProfileXmlConfigTests.
*
* @author Sam Brannen * @author Sam Brannen
* @since 3.1 * @since 3.1
*/ */

View File

@ -23,8 +23,6 @@ import org.junit.Test;
import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ActiveProfiles;
/** /**
* TODO Document DefaultProfileXmlConfigTests.
*
* @author Sam Brannen * @author Sam Brannen
* @since 3.1 * @since 3.1
*/ */