[SPR-8386][SPR-8387] Redesign of DelegatingSmartContextLoader and the SmartContextLoader SPI:
- Removed generatesDefaults() and supports() from the SmartContextLoader SPI and modified the DelegatingSmartContextLoader algorithm accordingly. - DelegatingSmartContextLoader no longer operates on a list of candidate loaders but rather on explicit instances of GenericXmlContextLoader and AnnotationConfigContextLoader. - Updated Javadoc regarding DelegatingSmartContextLoader as the new default loader. - Updated and polished Javadoc regarding changes in 3.1. - Now enforcing @ContextConfiguration's restriction on declaring locations or classes but not both.
This commit is contained in:
@@ -103,8 +103,8 @@ public @interface ContextConfiguration {
|
||||
* for details on the default configuration classes that will be used if none
|
||||
* are specified.
|
||||
*
|
||||
* <p>Note that this attribute may <strong>not</strong> be used in
|
||||
* conjunction with {@link #locations} or {@link #value}.
|
||||
* <p>This attribute may <strong>not</strong> be used in conjunction with
|
||||
* {@link #locations} or {@link #value}.
|
||||
* @since 3.1
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.test.context.support.AnnotationConfigContextLoader
|
||||
@@ -158,12 +158,12 @@ public @interface ContextConfiguration {
|
||||
* {@code ExtendedConfig} may therefore override those defined in
|
||||
* {@code BaseConfig}.
|
||||
* <pre class="code">
|
||||
* @ContextConfiguration(classes=BaseConfig.class, loader=AnnotationConfigContextLoader.class)
|
||||
* @ContextConfiguration(classes=BaseConfig.class)
|
||||
* public class BaseTest {
|
||||
* // ...
|
||||
* }
|
||||
*
|
||||
* @ContextConfiguration(classes=ExtendedConfig.class, loader=AnnotationConfigContextLoader.class)
|
||||
* @ContextConfiguration(classes=ExtendedConfig.class)
|
||||
* public class ExtendedTest extends BaseTest {
|
||||
* // ...
|
||||
* }
|
||||
@@ -172,7 +172,6 @@ public @interface ContextConfiguration {
|
||||
*/
|
||||
boolean inheritLocations() default true;
|
||||
|
||||
// TODO Update regarding default --> DelegatingSmartContextLoader
|
||||
/**
|
||||
* The type of {@link ContextLoader} (or {@link SmartContextLoader}) to use
|
||||
* for loading an {@link org.springframework.context.ApplicationContext
|
||||
@@ -184,10 +183,15 @@ public @interface ContextConfiguration {
|
||||
* loader, a default loader will be used instead.
|
||||
*
|
||||
* <p>The default concrete implementation chosen at runtime will be
|
||||
* {@link org.springframework.test.context.support.GenericXmlContextLoader
|
||||
* GenericXmlContextLoader}. Also check out
|
||||
* {@link org.springframework.test.context.support.DelegatingSmartContextLoader
|
||||
* DelegatingSmartContextLoader}. For further details on the default behavior
|
||||
* of various concrete {@code ContextLoaders}, check out the Javadoc for
|
||||
* {@link org.springframework.test.context.support.AbstractContextLoader
|
||||
* AbstractContextLoader}'s javadoc for details on the default behavior there.
|
||||
* AbstractContextLoader},
|
||||
* {@link org.springframework.test.context.support.GenericXmlContextLoader
|
||||
* GenericXmlContextLoader}, and
|
||||
* {@link org.springframework.test.context.support.AnnotationConfigContextLoader
|
||||
* AnnotationConfigContextLoader}.
|
||||
* @since 2.5
|
||||
*/
|
||||
Class<? extends ContextLoader> loader() default ContextLoader.class;
|
||||
|
||||
@@ -99,6 +99,8 @@ public class ContextConfigurationAttributes {
|
||||
* @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}
|
||||
* @throws IllegalArgumentException if the {@code declaringClass} or {@code contextLoaderClass} is
|
||||
* <code>null</code>, or if the {@code locations} and {@code classes} are both non-empty
|
||||
*/
|
||||
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
|
||||
boolean inheritLocations, Class<? extends ContextLoader> contextLoaderClass) {
|
||||
@@ -106,6 +108,16 @@ public class ContextConfigurationAttributes {
|
||||
Assert.notNull(declaringClass, "declaringClass must not be null");
|
||||
Assert.notNull(contextLoaderClass, "contextLoaderClass must not be null");
|
||||
|
||||
if (!ObjectUtils.isEmpty(locations) && !ObjectUtils.isEmpty(classes)) {
|
||||
String msg = String.format(
|
||||
"Test class [%s] has been configured with @ContextConfiguration's 'locations' (or 'value') %s "
|
||||
+ "and 'classes' %s attributes. Only one declaration of resources "
|
||||
+ "is permitted per @ContextConfiguration annotation.", declaringClass.getName(),
|
||||
ObjectUtils.nullSafeToString(locations), ObjectUtils.nullSafeToString(classes));
|
||||
logger.error(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
|
||||
this.declaringClass = declaringClass;
|
||||
this.locations = locations;
|
||||
this.classes = classes;
|
||||
@@ -169,16 +181,38 @@ public class ContextConfigurationAttributes {
|
||||
this.classes = classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this {@code ContextConfigurationAttributes} instance has
|
||||
* path-based resource locations.
|
||||
* @return <code>true</code> if the {@link #getLocations() locations} array is not empty
|
||||
* @see #hasResources()
|
||||
* @see #hasClasses()
|
||||
*/
|
||||
public boolean hasLocations() {
|
||||
return !ObjectUtils.isEmpty(getLocations());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this {@code ContextConfigurationAttributes} instance has
|
||||
* class-based resources.
|
||||
* @return <code>true</code> if the {@link #getClasses() classes} array is not empty
|
||||
* @see #hasResources()
|
||||
* @see #hasLocations()
|
||||
*/
|
||||
public boolean hasClasses() {
|
||||
return !ObjectUtils.isEmpty(getClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this {@code ContextConfigurationAttributes} instance has
|
||||
* either path-based resource locations or class-based resources.
|
||||
* @return <code>true</code> if either the {@link #getLocations() locations}
|
||||
* or the {@link #getClasses() classes} array is not empty
|
||||
* @see #getLocations()
|
||||
* @see #getClasses()
|
||||
* @see #hasLocations()
|
||||
* @see #hasClasses()
|
||||
*/
|
||||
public boolean hasResources() {
|
||||
return !ObjectUtils.isEmpty(getLocations()) || !ObjectUtils.isEmpty(getClasses());
|
||||
return hasLocations() || hasClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,34 +22,37 @@ import org.springframework.context.ApplicationContext;
|
||||
* <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>The {@code SmartContextLoader} SPI supersedes the {@link ContextLoader}
|
||||
* SPI introduced in Spring 2.5: a {@code SmartContextLoader} can process both
|
||||
* resource locations and configuration classes. Furthermore, a {@code SmartContextLoader}
|
||||
* 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()}.
|
||||
* <p>Clients of a {@code SmartContextLoader} should call
|
||||
* {@link #processContextConfiguration(ContextConfigurationAttributes)
|
||||
* processContextConfiguration()} prior to calling
|
||||
* {@link #loadContext(MergedContextConfiguration) loadContext()}. This gives a
|
||||
* {@code SmartContextLoader} the opportunity to provide 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()}.
|
||||
*
|
||||
* <p>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>Even though {@code SmartContextLoader} extends {@code ContextLoader},
|
||||
* clients should favor {@code SmartContextLoader}-specific methods over those
|
||||
* defined in {@code ContextLoader}, particularly because a
|
||||
* {@code SmartContextLoader} may choose not to support methods defined in
|
||||
* the {@code ContextLoader} 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.DelegatingSmartContextLoader DelegatingSmartContextLoader}</li>
|
||||
* <li>{@link org.springframework.test.context.support.AnnotationConfigContextLoader AnnotationConfigContextLoader}</li>
|
||||
* <li>{@link org.springframework.test.context.support.GenericXmlContextLoader GenericXmlContextLoader}</li>
|
||||
* <li>{@link org.springframework.test.context.support.GenericPropertiesContextLoader GenericPropertiesContextLoader}</li>
|
||||
* </ul>
|
||||
*
|
||||
@@ -62,47 +65,25 @@ import org.springframework.context.ApplicationContext;
|
||||
*/
|
||||
public interface SmartContextLoader extends ContextLoader {
|
||||
|
||||
/**
|
||||
* 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(ContextConfigurationAttributes)
|
||||
*/
|
||||
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
|
||||
* or <code>classes</code> in the supplied {@link ContextConfigurationAttributes},
|
||||
* <em>generate</em> default configuration locations, or <em>detect</em>
|
||||
* default configuration classes if the supplied values are <code>null</code>
|
||||
* or empty.
|
||||
* <p><b>Note</b>: in contrast to a standard {@code ContextLoader}, a
|
||||
* {@code SmartContextLoader} <b>must</b> <em>preemptively</em> verify that
|
||||
* a generated or detected 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.
|
||||
* this {@code SmartContextLoader} was not able to generate or detect defaults.
|
||||
* @param configAttributes the context configuration attributes to process
|
||||
* @see #generatesDefaults()
|
||||
*/
|
||||
void processContextConfiguration(ContextConfigurationAttributes configAttributes);
|
||||
|
||||
/**
|
||||
* TODO Document supports(MergedContextConfiguration).
|
||||
*
|
||||
* @param mergedConfig
|
||||
* @return
|
||||
*/
|
||||
boolean supports(MergedContextConfiguration mergedConfig);
|
||||
|
||||
/**
|
||||
* Loads a new {@link ApplicationContext context} based on the supplied
|
||||
* {@link MergedContextConfiguration merged context configuration},
|
||||
@@ -111,7 +92,7 @@ public interface SmartContextLoader extends ContextLoader {
|
||||
* <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
|
||||
* {@code SmartContextLoader}. 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
|
||||
@@ -119,10 +100,10 @@ public interface SmartContextLoader extends ContextLoader {
|
||||
* 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
|
||||
* {@code SmartContextLoader} <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.,
|
||||
* freeing of 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
|
||||
|
||||
@@ -54,32 +54,30 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
|
||||
/**
|
||||
* Delegates to {@link #TestContext(Class, ContextCache, String)} with a
|
||||
* value of <code>null</code> for the default <code>ContextLoader</code>
|
||||
* class name.
|
||||
* value of <code>null</code> for the default {@code ContextLoader} class name.
|
||||
*/
|
||||
TestContext(Class<?> testClass, ContextCache contextCache) {
|
||||
this(testClass, contextCache, null);
|
||||
}
|
||||
|
||||
// TODO Update regarding default --> DelegatingSmartContextLoader
|
||||
/**
|
||||
* Construct a new test context for the supplied {@link Class test class}
|
||||
* and {@link ContextCache context cache} and parse the corresponding
|
||||
* {@link ContextConfiguration @ContextConfiguration} annotation, if
|
||||
* present.
|
||||
* <p>If the supplied class name for the default <code>ContextLoader</code>
|
||||
* is <code>null</code> or <em>empty</em> and no <code>ContextLoader</code>
|
||||
* class is explicitly supplied via the
|
||||
* <code>@ContextConfiguration</code> annotation, a
|
||||
* {@link org.springframework.test.context.support.GenericXmlContextLoader
|
||||
* GenericXmlContextLoader} will be used instead.
|
||||
* <p>If the supplied class name for the default {@code ContextLoader}
|
||||
* is <code>null</code> or <em>empty</em> and no concrete {@code ContextLoader}
|
||||
* class is explicitly supplied via the {@code @ContextConfiguration}
|
||||
* annotation, a
|
||||
* {@link org.springframework.test.context.support.DelegatingSmartContextLoader
|
||||
* DelegatingSmartContextLoader} will be used instead.
|
||||
* @param testClass the test class for which the test context should be
|
||||
* constructed (must not be <code>null</code>)
|
||||
* @param contextCache the context cache from which the constructed test
|
||||
* context should retrieve application contexts (must not be
|
||||
* <code>null</code>)
|
||||
* @param defaultContextLoaderClassName the name of the default
|
||||
* <code>ContextLoader</code> class to use (may be <code>null</code>)
|
||||
* {@code ContextLoader} class to use (may be <code>null</code>)
|
||||
*/
|
||||
TestContext(Class<?> testClass, ContextCache contextCache, String defaultContextLoaderClassName) {
|
||||
Assert.notNull(testClass, "Test class must not be null");
|
||||
@@ -110,7 +108,7 @@ public class TestContext extends AttributeAccessorSupport {
|
||||
|
||||
/**
|
||||
* Load an <code>ApplicationContext</code> for this test context using the
|
||||
* configured <code>ContextLoader</code> and configuration attributes.
|
||||
* configured {@code ContextLoader} and configuration attributes.
|
||||
* @throws Exception if an error occurs while loading the application context
|
||||
*/
|
||||
private ApplicationContext loadApplicationContext() throws Exception {
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.support.ResourcePatternUtils;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
@@ -40,9 +39,7 @@ import org.springframework.util.StringUtils;
|
||||
* <p>As of Spring 3.1, <code>AbstractContextLoader</code> also provides a basis
|
||||
* for all concrete implementations of the {@link SmartContextLoader} SPI. For
|
||||
* backwards compatibility with the {@code ContextLoader} SPI,
|
||||
* {@link #processContextConfiguration()} delegates to
|
||||
* {@link #processLocations()}, and {@link #generatesDefaults()} delegates to
|
||||
* {@link #isGenerateDefaultLocations()}.
|
||||
* {@link #processContextConfiguration()} delegates to {@link #processLocations()}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @author Juergen Hoeller
|
||||
@@ -54,23 +51,12 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AbstractContextLoader.class);
|
||||
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[] {};
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
private static final String SLASH = "/";
|
||||
|
||||
|
||||
// --- SmartContextLoader -----------------------------------------------
|
||||
|
||||
/**
|
||||
* For backwards compatibility with the {@link ContextLoader} SPI, the
|
||||
* default implementation simply delegates to
|
||||
* {@link #isGenerateDefaultLocations()}.
|
||||
* @see org.springframework.test.context.SmartContextLoader#generatesDefaults()
|
||||
* @see #isGenerateDefaultLocations()
|
||||
*/
|
||||
public boolean generatesDefaults() {
|
||||
return isGenerateDefaultLocations();
|
||||
}
|
||||
|
||||
/**
|
||||
* For backwards compatibility with the {@link ContextLoader} SPI, the
|
||||
* default implementation simply delegates to {@link #processLocations()},
|
||||
@@ -83,6 +69,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* the supplied configuration attributes.
|
||||
* <p>Can be overridden in subclasses — for example, to process
|
||||
* configuration classes instead of resource locations.
|
||||
* @since 3.1
|
||||
* @see #processLocations()
|
||||
*/
|
||||
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
|
||||
@@ -91,13 +78,6 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
configAttributes.setLocations(processedLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document default supports(MergedContextConfiguration) implementation.
|
||||
*/
|
||||
public boolean supports(MergedContextConfiguration mergedConfig) {
|
||||
return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
}
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -114,6 +94,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* @param locations the unmodified locations to use for loading the
|
||||
* application context (can be <code>null</code> or empty)
|
||||
* @return a processed array of application context resource locations
|
||||
* @since 2.5
|
||||
* @see #isGenerateDefaultLocations()
|
||||
* @see #generateDefaultLocations()
|
||||
* @see #modifyLocations()
|
||||
@@ -142,6 +123,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* <em>default location generation</em> strategy.
|
||||
* @param clazz the class for which the default locations are to be generated
|
||||
* @return an array of default application context resource locations
|
||||
* @since 2.5
|
||||
* @see #getResourceSuffix()
|
||||
*/
|
||||
protected String[] generateDefaultLocations(Class<?> clazz) {
|
||||
@@ -178,6 +160,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* @param clazz the class with which the locations are associated
|
||||
* @param locations the resource locations to be modified
|
||||
* @return an array of modified application context resource locations
|
||||
* @since 2.5
|
||||
*/
|
||||
protected String[] modifyLocations(Class<?> clazz, String... locations) {
|
||||
String[] modifiedLocations = new String[locations.length];
|
||||
@@ -203,6 +186,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* {@link #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
|
||||
* @since 2.5
|
||||
*/
|
||||
protected boolean isGenerateDefaultLocations() {
|
||||
return true;
|
||||
@@ -213,6 +197,7 @@ public abstract class AbstractContextLoader implements SmartContextLoader {
|
||||
* locations when generating default locations.
|
||||
* <p>Must be implemented by subclasses.
|
||||
* @return the resource suffix; should not be <code>null</code> or empty
|
||||
* @since 2.5
|
||||
* @see #generateDefaultLocations()
|
||||
*/
|
||||
protected abstract String getResourceSuffix();
|
||||
|
||||
@@ -86,6 +86,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* @return a new application context
|
||||
* @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration)
|
||||
* @see GenericApplicationContext
|
||||
* @since 3.1
|
||||
*/
|
||||
public final ConfigurableApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -131,6 +132,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* @see org.springframework.test.context.ContextLoader#loadContext
|
||||
* @see GenericApplicationContext
|
||||
* @see #loadContext(MergedContextConfiguration)
|
||||
* @since 2.5
|
||||
*/
|
||||
public final ConfigurableApplicationContext loadContext(String... locations) throws Exception {
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -159,6 +161,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* @see GenericApplicationContext#setAllowBeanDefinitionOverriding
|
||||
* @see GenericApplicationContext#setResourceLoader
|
||||
* @see GenericApplicationContext#setId
|
||||
* @since 2.5
|
||||
*/
|
||||
protected void prepareContext(GenericApplicationContext context) {
|
||||
}
|
||||
@@ -175,6 +178,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* @see DefaultListableBeanFactory#setAllowEagerClassLoading
|
||||
* @see DefaultListableBeanFactory#setAllowCircularReferences
|
||||
* @see DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping
|
||||
* @since 2.5
|
||||
*/
|
||||
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
|
||||
}
|
||||
@@ -194,8 +198,8 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* registering bean definitions.
|
||||
* @param context the context into which the bean definitions should be loaded
|
||||
* @param mergedConfig the merged context configuration
|
||||
* @since 3.1
|
||||
* @see #loadContext(MergedContextConfiguration)
|
||||
* @since 3.1
|
||||
*/
|
||||
protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
createBeanDefinitionReader(context).loadBeanDefinitions(mergedConfig.getLocations());
|
||||
@@ -210,6 +214,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* @see #loadContext(String...)
|
||||
* @see #loadBeanDefinitions
|
||||
* @see BeanDefinitionReader
|
||||
* @since 2.5
|
||||
*/
|
||||
protected abstract BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context);
|
||||
|
||||
@@ -222,6 +227,7 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader
|
||||
* @param context the newly created application context
|
||||
* @see #loadContext(MergedContextConfiguration)
|
||||
* @see #loadContext(String...)
|
||||
* @since 2.5
|
||||
*/
|
||||
protected void customizeContext(GenericApplicationContext context) {
|
||||
}
|
||||
|
||||
@@ -64,31 +64,23 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
||||
/**
|
||||
* Process configuration classes in the supplied {@link ContextConfigurationAttributes}.
|
||||
* <p>If the configuration classes are <code>null</code> or empty and
|
||||
* {@link #generatesDefaults()} returns <code>true</code>, this
|
||||
* {@link #isGenerateDefaultLocations()} returns <code>true</code>, this
|
||||
* <code>SmartContextLoader</code> will attempt to
|
||||
* {@link #generateDefaultConfigurationClasses generate default configuration classes}.
|
||||
* Otherwise, properties in the supplied configuration attributes will not
|
||||
* be modified.
|
||||
* @param configAttributes the context configuration attributes to process
|
||||
* @see org.springframework.test.context.SmartContextLoader#processContextConfiguration()
|
||||
* @see #generatesDefaults()
|
||||
* @see #isGenerateDefaultLocations()
|
||||
* @see #generateDefaultConfigurationClasses()
|
||||
*/
|
||||
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
|
||||
if (ObjectUtils.isEmpty(configAttributes.getClasses()) && generatesDefaults()) {
|
||||
if (ObjectUtils.isEmpty(configAttributes.getClasses()) && isGenerateDefaultLocations()) {
|
||||
Class<?>[] defaultConfigClasses = generateDefaultConfigurationClasses(configAttributes.getDeclaringClass());
|
||||
configAttributes.setClasses(defaultConfigClasses);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden supports(MergedContextConfiguration) implementation.
|
||||
*/
|
||||
@Override
|
||||
public boolean supports(MergedContextConfiguration mergedConfig) {
|
||||
return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
}
|
||||
|
||||
// --- AnnotationConfigContextLoader ---------------------------------------
|
||||
|
||||
private boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
|
||||
@@ -99,7 +91,7 @@ public class AnnotationConfigContextLoader extends AbstractGenericContextLoader
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Class} meets the criteria for being
|
||||
* considered as a <em>default configuration class</em> candidate.
|
||||
* considered a <em>default configuration class</em> candidate.
|
||||
* <p>Specifically, such candidates:
|
||||
* <ul>
|
||||
* <li>must not be <code>null</code></li>
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* TODO Document DelegatingSmartContextLoader.
|
||||
@@ -41,92 +42,106 @@ public class DelegatingSmartContextLoader implements SmartContextLoader {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(DelegatingSmartContextLoader.class);
|
||||
|
||||
private final List<? extends SmartContextLoader> candidates = Arrays.asList(new GenericXmlContextLoader(),
|
||||
new AnnotationConfigContextLoader());
|
||||
private final SmartContextLoader xmlLoader = new GenericXmlContextLoader();
|
||||
private final SmartContextLoader annotationLoader = new AnnotationConfigContextLoader();
|
||||
|
||||
|
||||
// --- SmartContextLoader --------------------------------------------------
|
||||
|
||||
/**
|
||||
* TODO Document generatesDefaults() implementation.
|
||||
*/
|
||||
public boolean generatesDefaults() {
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
if (loader.generatesDefaults()) {
|
||||
return true;
|
||||
}
|
||||
private static String name(SmartContextLoader loader) {
|
||||
return loader.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
private static void delegateProcessing(SmartContextLoader loader, ContextConfigurationAttributes configAttributes) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to process context configuration [%s].", name(loader),
|
||||
configAttributes));
|
||||
}
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
}
|
||||
|
||||
private static boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
||||
if (loader instanceof AnnotationConfigContextLoader) {
|
||||
return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
}
|
||||
else {
|
||||
return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document processContextConfiguration() implementation.
|
||||
*/
|
||||
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
|
||||
public void processContextConfiguration(final ContextConfigurationAttributes configAttributes) {
|
||||
|
||||
final boolean originallyHadResources = configAttributes.hasResources();
|
||||
if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Cannot process locations AND configuration classes for context "
|
||||
+ "configuration [%s]; configure one or the other, but not both.", configAttributes));
|
||||
}
|
||||
|
||||
// If the original locations and classes were not empty, there's no
|
||||
// need to bother with default generation checks; just let each
|
||||
// If the original locations or classes were not empty, there's no
|
||||
// need to bother with default detection checks; just let the respective
|
||||
// loader process the configuration.
|
||||
if (originallyHadResources) {
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to process context configuration [%s].",
|
||||
loader.getClass().getName(), configAttributes));
|
||||
}
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
}
|
||||
if (configAttributes.hasLocations()) {
|
||||
delegateProcessing(xmlLoader, configAttributes);
|
||||
}
|
||||
else if (generatesDefaults()) {
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
boolean defaultResourcesAlreadyGenerated = configAttributes.hasResources();
|
||||
// If defaults haven't already been generated and the loader
|
||||
// claims to generate defaults, let it process the
|
||||
// configuration.
|
||||
if (!defaultResourcesAlreadyGenerated && loader.generatesDefaults()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Delegating to %s to detect defaults for context configuration [%s].",
|
||||
loader.getClass().getName(), configAttributes));
|
||||
}
|
||||
else if (configAttributes.hasClasses()) {
|
||||
delegateProcessing(annotationLoader, configAttributes);
|
||||
}
|
||||
else {
|
||||
// Else attempt to detect defaults...
|
||||
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
// Let the XML loader process the configuration.
|
||||
delegateProcessing(xmlLoader, configAttributes);
|
||||
boolean xmlLoaderDetectedDefaults = configAttributes.hasLocations();
|
||||
|
||||
if (configAttributes.hasResources()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("SmartContextLoader candidate %s "
|
||||
+ "detected defaults for context configuration [%s].", loader, configAttributes));
|
||||
}
|
||||
}
|
||||
if (xmlLoaderDetectedDefaults) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("%s detected default locations for context configuration [%s].",
|
||||
name(xmlLoader), configAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
// If any loader claims to generate defaults but none actually did,
|
||||
// throw an exception.
|
||||
if (configAttributes.hasClasses()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"%s should NOT have detected default configuration classes for context configuration [%s].",
|
||||
name(xmlLoader), configAttributes));
|
||||
}
|
||||
|
||||
// Now let the annotation loader process the configuration.
|
||||
delegateProcessing(annotationLoader, configAttributes);
|
||||
|
||||
if (configAttributes.hasClasses()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format(
|
||||
"%s detected default configuration classes for context configuration [%s].",
|
||||
name(annotationLoader), configAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
if (!xmlLoaderDetectedDefaults && configAttributes.hasLocations()) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"%s should NOT have detected default locations for context configuration [%s].",
|
||||
name(annotationLoader), configAttributes));
|
||||
}
|
||||
|
||||
// If neither loader detected defaults, throw an exception.
|
||||
if (!configAttributes.hasResources()) {
|
||||
throw new IllegalStateException(String.format("None of the SmartContextLoader candidates %s "
|
||||
+ "was able to detect defaults for context configuration [%s].", candidates, configAttributes));
|
||||
throw new IllegalStateException(String.format(
|
||||
"Neither %s nor %s was able to detect defaults for context configuration [%s].", name(xmlLoader),
|
||||
name(annotationLoader), configAttributes));
|
||||
}
|
||||
|
||||
// TODO Throw exception if defaults were generated for both
|
||||
// locations and configuration classes.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document supports(MergedContextConfiguration) implementation.
|
||||
*/
|
||||
public boolean supports(MergedContextConfiguration mergedConfig) {
|
||||
Assert.notNull(mergedConfig, "mergedConfig must not be null");
|
||||
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
if (loader.supports(mergedConfig)) {
|
||||
return true;
|
||||
if (configAttributes.hasLocations() && configAttributes.hasClasses()) {
|
||||
String message = String.format(
|
||||
"Configuration error: both default locations AND default configuration classes "
|
||||
+ "were detected for context configuration [%s]; configure one or the other, but not both.",
|
||||
configAttributes);
|
||||
logger.error(message);
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,20 +150,23 @@ public class DelegatingSmartContextLoader implements SmartContextLoader {
|
||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
Assert.notNull(mergedConfig, "mergedConfig must not be null");
|
||||
|
||||
List<SmartContextLoader> candidates = Arrays.asList(xmlLoader, annotationLoader);
|
||||
|
||||
// Determine if each loader can load a context from the mergedConfig. If
|
||||
// it can, let it; otherwise, keep iterating.
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
// Ask each loader if it can load a context from the mergedConfig.
|
||||
// If it can, let it; otherwise, keep iterating.
|
||||
if (loader.supports(mergedConfig)) {
|
||||
if (supports(loader, mergedConfig)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to load context from [%s].",
|
||||
loader.getClass().getName(), mergedConfig));
|
||||
logger.debug(String.format("Delegating to %s to load context from [%s].", name(loader),
|
||||
mergedConfig));
|
||||
}
|
||||
return loader.loadContext(mergedConfig);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format("None of the SmartContextLoader candidates %s "
|
||||
+ "was able to load an ApplicationContext from [%s].", candidates, mergedConfig));
|
||||
throw new IllegalStateException(String.format(
|
||||
"Neither %s nor %s was able to load an ApplicationContext from [%s].", name(xmlLoader),
|
||||
name(annotationLoader), mergedConfig));
|
||||
}
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
||||
@@ -38,8 +38,8 @@ import org.springframework.test.context.support.GenericPropertiesContextLoader;
|
||||
*/
|
||||
public class ContextLoaderUtilsTests {
|
||||
|
||||
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[] {};
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[] {};
|
||||
private static final Class<?>[] EMPTY_CLASS_ARRAY = new Class<?>[0];
|
||||
private static final String[] EMPTY_STRING_ARRAY = new String[0];
|
||||
|
||||
|
||||
private void assertAttributes(ContextConfigurationAttributes attributes, Class<?> expectedDeclaringClass,
|
||||
@@ -52,13 +52,23 @@ public class ContextLoaderUtilsTests {
|
||||
assertEquals(expectedContextLoaderClass, attributes.getContextLoaderClass());
|
||||
}
|
||||
|
||||
private void assertFooAttributes(ContextConfigurationAttributes attributes) {
|
||||
assertAttributes(attributes, Foo.class, new String[] { "/foo.xml" }, new Class<?>[] { FooConfig.class },
|
||||
private void assertLocationsFooAttributes(ContextConfigurationAttributes attributes) {
|
||||
assertAttributes(attributes, LocationsFoo.class, new String[] { "/foo.xml" }, EMPTY_CLASS_ARRAY,
|
||||
ContextLoader.class, false);
|
||||
}
|
||||
|
||||
private void assertBarAttributes(ContextConfigurationAttributes attributes) {
|
||||
assertAttributes(attributes, Bar.class, new String[] { "/bar.xml" }, new Class<?>[] { BarConfig.class },
|
||||
private void assertClassesFooAttributes(ContextConfigurationAttributes attributes) {
|
||||
assertAttributes(attributes, ClassesFoo.class, EMPTY_STRING_ARRAY, new Class<?>[] { FooConfig.class },
|
||||
ContextLoader.class, false);
|
||||
}
|
||||
|
||||
private void assertLocationsBarAttributes(ContextConfigurationAttributes attributes) {
|
||||
assertAttributes(attributes, LocationsBar.class, new String[] { "/bar.xml" }, EMPTY_CLASS_ARRAY,
|
||||
AnnotationConfigContextLoader.class, true);
|
||||
}
|
||||
|
||||
private void assertClassesBarAttributes(ContextConfigurationAttributes attributes) {
|
||||
assertAttributes(attributes, ClassesBar.class, EMPTY_STRING_ARRAY, new Class<?>[] { BarConfig.class },
|
||||
AnnotationConfigContextLoader.class, true);
|
||||
}
|
||||
|
||||
@@ -90,20 +100,37 @@ public class ContextLoaderUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextConfigurationAttributesWithLocalAnnotation() {
|
||||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(Foo.class);
|
||||
public void resolveContextConfigurationAttributesWithLocalAnnotationAndLocations() {
|
||||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(LocationsFoo.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(1, attributesList.size());
|
||||
assertFooAttributes(attributesList.get(0));
|
||||
assertLocationsFooAttributes(attributesList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextConfigurationAttributesWithLocalAndInheritedAnnotations() {
|
||||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(Bar.class);
|
||||
public void resolveContextConfigurationAttributesWithLocalAnnotationAndClasses() {
|
||||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(ClassesFoo.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(1, attributesList.size());
|
||||
assertClassesFooAttributes(attributesList.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextConfigurationAttributesWithLocalAndInheritedAnnotationsAndLocations() {
|
||||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(LocationsBar.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(2, attributesList.size());
|
||||
assertFooAttributes(attributesList.get(0));
|
||||
assertBarAttributes(attributesList.get(1));
|
||||
assertLocationsFooAttributes(attributesList.get(0));
|
||||
assertLocationsBarAttributes(attributesList.get(1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveContextConfigurationAttributesWithLocalAndInheritedAnnotationsAndClasses() {
|
||||
List<ContextConfigurationAttributes> attributesList = ContextLoaderUtils.resolveContextConfigurationAttributes(ClassesBar.class);
|
||||
assertNotNull(attributesList);
|
||||
assertEquals(2, attributesList.size());
|
||||
assertClassesFooAttributes(attributesList.get(0));
|
||||
assertClassesBarAttributes(attributesList.get(1));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
@@ -124,33 +151,62 @@ public class ContextLoaderUtilsTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAnnotation() {
|
||||
Class<?> testClass = Foo.class;
|
||||
public void buildMergedContextConfigurationWithLocalAnnotationAndLocations() {
|
||||
Class<?> testClass = LocationsFoo.class;
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
||||
EMPTY_CLASS_ARRAY, DelegatingSmartContextLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAnnotationAndClasses() {
|
||||
Class<?> testClass = ClassesFoo.class;
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, EMPTY_STRING_ARRAY,
|
||||
new Class<?>[] { FooConfig.class }, DelegatingSmartContextLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAnnotationAndOverriddenContextLoader() {
|
||||
Class<?> testClass = Foo.class;
|
||||
public void buildMergedContextConfigurationWithLocalAnnotationAndOverriddenContextLoaderAndLocations() {
|
||||
Class<?> testClass = LocationsFoo.class;
|
||||
Class<? extends ContextLoader> expectedContextLoaderClass = GenericPropertiesContextLoader.class;
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass,
|
||||
expectedContextLoaderClass.getName());
|
||||
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, new String[] { "classpath:/foo.xml" },
|
||||
EMPTY_CLASS_ARRAY, expectedContextLoaderClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAnnotationAndOverriddenContextLoaderAndClasses() {
|
||||
Class<?> testClass = ClassesFoo.class;
|
||||
Class<? extends ContextLoader> expectedContextLoaderClass = GenericPropertiesContextLoader.class;
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass,
|
||||
expectedContextLoaderClass.getName());
|
||||
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, EMPTY_STRING_ARRAY,
|
||||
new Class<?>[] { FooConfig.class }, expectedContextLoaderClass);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAndInheritedAnnotations() {
|
||||
Class<?> testClass = Bar.class;
|
||||
public void buildMergedContextConfigurationWithLocalAndInheritedAnnotationsAndLocations() {
|
||||
Class<?> testClass = LocationsBar.class;
|
||||
String[] expectedLocations = new String[] { "/foo.xml", "/bar.xml" };
|
||||
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, expectedLocations, EMPTY_CLASS_ARRAY,
|
||||
AnnotationConfigContextLoader.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildMergedContextConfigurationWithLocalAndInheritedAnnotationsAndClasses() {
|
||||
Class<?> testClass = ClassesBar.class;
|
||||
Class<?>[] expectedClasses = new Class<?>[] { FooConfig.class, BarConfig.class };
|
||||
|
||||
MergedContextConfiguration mergedConfig = ContextLoaderUtils.buildMergedContextConfiguration(testClass, null);
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, expectedLocations, expectedClasses,
|
||||
assertMergedContextConfiguration(mergedConfig, testClass, EMPTY_STRING_ARRAY, expectedClasses,
|
||||
AnnotationConfigContextLoader.class);
|
||||
}
|
||||
|
||||
@@ -186,21 +242,28 @@ public class ContextLoaderUtilsTests {
|
||||
|
||||
@Test
|
||||
public void resolveActiveProfilesWithLocalAnnotation() {
|
||||
String[] profiles = ContextLoaderUtils.resolveActiveProfiles(Foo.class);
|
||||
String[] profiles = ContextLoaderUtils.resolveActiveProfiles(LocationsFoo.class);
|
||||
assertNotNull(profiles);
|
||||
assertArrayEquals(new String[] { "foo" }, profiles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveActiveProfilesWithInheritedAnnotation() {
|
||||
String[] profiles = ContextLoaderUtils.resolveActiveProfiles(InheritedFoo.class);
|
||||
public void resolveActiveProfilesWithInheritedAnnotationAndLocations() {
|
||||
String[] profiles = ContextLoaderUtils.resolveActiveProfiles(InheritedLocationsFoo.class);
|
||||
assertNotNull(profiles);
|
||||
assertArrayEquals(new String[] { "foo" }, profiles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveActiveProfilesWithInheritedAnnotationAndClasses() {
|
||||
String[] profiles = ContextLoaderUtils.resolveActiveProfiles(InheritedClassesFoo.class);
|
||||
assertNotNull(profiles);
|
||||
assertArrayEquals(new String[] { "foo" }, profiles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveActiveProfilesWithLocalAndInheritedAnnotations() {
|
||||
String[] profiles = ContextLoaderUtils.resolveActiveProfiles(Bar.class);
|
||||
String[] profiles = ContextLoaderUtils.resolveActiveProfiles(LocationsBar.class);
|
||||
assertNotNull(profiles);
|
||||
assertEquals(2, profiles.length);
|
||||
|
||||
@@ -245,25 +308,38 @@ public class ContextLoaderUtilsTests {
|
||||
private static class FooConfig {
|
||||
}
|
||||
|
||||
@ContextConfiguration(locations = "/foo.xml", classes = FooConfig.class, inheritLocations = false)
|
||||
@ContextConfiguration(locations = "/foo.xml", inheritLocations = false)
|
||||
@ActiveProfiles(profiles = "foo")
|
||||
private static class Foo {
|
||||
private static class LocationsFoo {
|
||||
}
|
||||
|
||||
private static class InheritedFoo extends Foo {
|
||||
@ContextConfiguration(classes = FooConfig.class, inheritLocations = false)
|
||||
@ActiveProfiles(profiles = "foo")
|
||||
private static class ClassesFoo {
|
||||
}
|
||||
|
||||
private static class InheritedLocationsFoo extends LocationsFoo {
|
||||
}
|
||||
|
||||
private static class InheritedClassesFoo extends ClassesFoo {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
private static class BarConfig {
|
||||
}
|
||||
|
||||
@ContextConfiguration(locations = "/bar.xml", classes = BarConfig.class, inheritLocations = true, loader = AnnotationConfigContextLoader.class)
|
||||
@ContextConfiguration(locations = "/bar.xml", inheritLocations = true, loader = AnnotationConfigContextLoader.class)
|
||||
@ActiveProfiles("bar")
|
||||
private static class Bar extends Foo {
|
||||
private static class LocationsBar extends LocationsFoo {
|
||||
}
|
||||
|
||||
@ContextConfiguration(classes = BarConfig.class, inheritLocations = true, loader = AnnotationConfigContextLoader.class)
|
||||
@ActiveProfiles("bar")
|
||||
private static class ClassesBar extends ClassesFoo {
|
||||
}
|
||||
|
||||
@ActiveProfiles(profiles = { "dog", "cat" }, inheritProfiles = false)
|
||||
private static class Animals extends Bar {
|
||||
private static class Animals extends LocationsBar {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @see DefaultLoaderDefaultConfigClassesBaseTests
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.springframework.test.context.support.DelegatingSmartContextLoader;
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @see DefaultConfigClassesBaseTests
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.test.context.support;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -50,12 +49,7 @@ public class DelegatingSmartContextLoaderTests {
|
||||
assertTrue(ObjectUtils.isEmpty(array));
|
||||
}
|
||||
|
||||
// --- SmartContextLoader --------------------------------------------------
|
||||
|
||||
@Test
|
||||
public void generatesDefaults() {
|
||||
assertTrue(loader.generatesDefaults());
|
||||
}
|
||||
// --- SmartContextLoader - processContextConfiguration() ------------------
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void processContextConfigurationWithoutLocationsAndConfigurationClassesForBogusTestClass() {
|
||||
@@ -82,6 +76,14 @@ public class DelegatingSmartContextLoaderTests {
|
||||
assertEmpty(configAttributes.getLocations());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void processContextConfigurationWithDefaultXmlConfigAndConfigurationClassGeneration() {
|
||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(
|
||||
ImproperDuplicateDefaultXmlAndConfigClassTestCase.class, EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true,
|
||||
ContextLoader.class);
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processContextConfigurationWithLocation() {
|
||||
String[] locations = new String[] { "classpath:/foo.xml" };
|
||||
@@ -102,39 +104,7 @@ public class DelegatingSmartContextLoaderTests {
|
||||
assertEmpty(configAttributes.getLocations());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void doesNotSupportNullConfig() {
|
||||
MergedContextConfiguration mergedConfig = null;
|
||||
loader.supports(mergedConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotSupportEmptyConfig() {
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), EMPTY_STRING_ARRAY,
|
||||
EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
||||
assertFalse(loader.supports(mergedConfig));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotSupportLocationsAndConfigurationClasses() {
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(),
|
||||
new String[] { "foo.xml" }, new Class<?>[] { getClass() }, EMPTY_STRING_ARRAY, loader);
|
||||
assertFalse(loader.supports(mergedConfig));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsLocations() {
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(),
|
||||
new String[] { "foo.xml" }, EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
||||
assertTrue(loader.supports(mergedConfig));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsConfigurationClasses() {
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), EMPTY_STRING_ARRAY,
|
||||
new Class<?>[] { getClass() }, EMPTY_STRING_ARRAY, loader);
|
||||
assertTrue(loader.supports(mergedConfig));
|
||||
}
|
||||
// --- SmartContextLoader - loadContext() ----------------------------------
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void loadContextWithNullConfig() throws Exception {
|
||||
@@ -187,6 +157,8 @@ public class DelegatingSmartContextLoaderTests {
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
static class XmlTestCase {
|
||||
}
|
||||
|
||||
@@ -202,4 +174,13 @@ public class DelegatingSmartContextLoaderTests {
|
||||
}
|
||||
}
|
||||
|
||||
static class ImproperDuplicateDefaultXmlAndConfigClassTestCase {
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
// intentionally empty: we just need the class to be present to fail
|
||||
// the test
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:c="http://www.springframework.org/schema/c"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
|
||||
|
||||
<!-- intentionally empty: we just need the file to be present to fail the test -->
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user