[SPR-8387] Fleshed out the implementation of DelegatingSmartContextLoader and corresponding tests.
This commit is contained in:
parent
9d7bc31f0d
commit
f874ed9790
|
|
@ -102,6 +102,10 @@ public class ContextConfigurationAttributes {
|
|||
*/
|
||||
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
|
||||
boolean inheritLocations, Class<? extends ContextLoader> contextLoaderClass) {
|
||||
|
||||
Assert.notNull(declaringClass, "declaringClass must not be null");
|
||||
Assert.notNull(contextLoaderClass, "contextLoaderClass must not be null");
|
||||
|
||||
this.declaringClass = declaringClass;
|
||||
this.locations = locations;
|
||||
this.classes = classes;
|
||||
|
|
@ -115,7 +119,7 @@ public class ContextConfigurationAttributes {
|
|||
* @return the declaring class; never <code>null</code>
|
||||
*/
|
||||
public Class<?> getDeclaringClass() {
|
||||
return this.declaringClass;
|
||||
return declaringClass;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -130,7 +134,7 @@ public class ContextConfigurationAttributes {
|
|||
* @see #setLocations()
|
||||
*/
|
||||
public String[] getLocations() {
|
||||
return this.locations;
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -153,7 +157,7 @@ public class ContextConfigurationAttributes {
|
|||
* @see #setClasses()
|
||||
*/
|
||||
public Class<?>[] getClasses() {
|
||||
return this.classes;
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -184,7 +188,7 @@ public class ContextConfigurationAttributes {
|
|||
* @see ContextConfiguration#inheritLocations
|
||||
*/
|
||||
public boolean isInheritLocations() {
|
||||
return this.inheritLocations;
|
||||
return inheritLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -194,7 +198,7 @@ public class ContextConfigurationAttributes {
|
|||
* @see ContextConfiguration#loader
|
||||
*/
|
||||
public Class<? extends ContextLoader> getContextLoaderClass() {
|
||||
return this.contextLoaderClass;
|
||||
return contextLoaderClass;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -204,11 +208,11 @@ public class ContextConfigurationAttributes {
|
|||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)//
|
||||
.append("declaringClass", this.declaringClass)//
|
||||
.append("locations", ObjectUtils.nullSafeToString(this.locations))//
|
||||
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
||||
.append("inheritLocations", this.inheritLocations)//
|
||||
.append("contextLoaderClass", this.contextLoaderClass)//
|
||||
.append("declaringClass", declaringClass.getName())//
|
||||
.append("locations", ObjectUtils.nullSafeToString(locations))//
|
||||
.append("classes", ObjectUtils.nullSafeToString(classes))//
|
||||
.append("inheritLocations", inheritLocations)//
|
||||
.append("contextLoaderClass", contextLoaderClass.getName())//
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ public class MergedContextConfiguration {
|
|||
* <code>MergedContextConfiguration</code>.
|
||||
*/
|
||||
public Class<?> getTestClass() {
|
||||
return this.testClass;
|
||||
return testClass;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -144,7 +144,7 @@ public class MergedContextConfiguration {
|
|||
* {@link #getTestClass() test class}.
|
||||
*/
|
||||
public String[] getLocations() {
|
||||
return this.locations;
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -152,7 +152,7 @@ public class MergedContextConfiguration {
|
|||
* {@link #getTestClass() test class}.
|
||||
*/
|
||||
public Class<?>[] getClasses() {
|
||||
return this.classes;
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -160,7 +160,7 @@ public class MergedContextConfiguration {
|
|||
* {@link #getTestClass() test class}.
|
||||
*/
|
||||
public String[] getActiveProfiles() {
|
||||
return this.activeProfiles;
|
||||
return activeProfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -168,7 +168,7 @@ public class MergedContextConfiguration {
|
|||
* {@link #getTestClass() test class}.
|
||||
*/
|
||||
public ContextLoader getContextLoader() {
|
||||
return this.contextLoader;
|
||||
return contextLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -180,7 +180,7 @@ public class MergedContextConfiguration {
|
|||
* that was loaded using properties of this <code>MergedContextConfiguration</code>.
|
||||
*/
|
||||
public String getContextKey() {
|
||||
return this.contextKey;
|
||||
return contextKey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -190,12 +190,12 @@ public class MergedContextConfiguration {
|
|||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this)//
|
||||
.append("testClass", this.testClass)//
|
||||
.append("locations", ObjectUtils.nullSafeToString(this.locations))//
|
||||
.append("classes", ObjectUtils.nullSafeToString(this.classes))//
|
||||
.append("activeProfiles", ObjectUtils.nullSafeToString(this.activeProfiles))//
|
||||
.append("testClass", testClass)//
|
||||
.append("locations", ObjectUtils.nullSafeToString(locations))//
|
||||
.append("classes", ObjectUtils.nullSafeToString(classes))//
|
||||
.append("activeProfiles", ObjectUtils.nullSafeToString(activeProfiles))//
|
||||
.append("contextLoader", nullSafeToString(contextLoader))//
|
||||
.append("contextKey", this.contextKey)//
|
||||
.append("contextKey", contextKey)//
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,8 @@ import org.springframework.context.ApplicationContext;
|
|||
* {@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>,
|
||||
*
|
||||
* <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
|
||||
|
|
@ -63,9 +64,8 @@ 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>
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -66,34 +66,50 @@ public class DelegatingSmartContextLoader implements SmartContextLoader {
|
|||
|
||||
final boolean originallyHadResources = configAttributes.hasResources();
|
||||
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Potentially delegating to %s to process context configuration [%s].",
|
||||
loader.getClass().getName(), configAttributes));
|
||||
}
|
||||
|
||||
// If the original locations and classes were not empty, there's no
|
||||
// need to bother with default generation checks; just let each
|
||||
// loader process the configuration.
|
||||
if (originallyHadResources) {
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
}
|
||||
// Otherwise, if the loader claims to generate defaults, let it
|
||||
// process the configuration.
|
||||
else if (loader.generatesDefaults()) {
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
if (configAttributes.hasResources() && logger.isInfoEnabled()) {
|
||||
logger.info(String.format("SmartContextLoader candidate %s "
|
||||
+ "generated defaults for context configuration [%s].", loader, configAttributes));
|
||||
// If the original locations and classes were not empty, there's no
|
||||
// need to bother with default generation checks; just let each
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
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 generate defaults for context configuration [%s].",
|
||||
loader.getClass().getName(), configAttributes));
|
||||
}
|
||||
|
||||
// If any loader claims to generate defaults but none actually did,
|
||||
// throw an exception.
|
||||
if (generatesDefaults() && !originallyHadResources && !configAttributes.hasResources()) {
|
||||
throw new IllegalStateException(String.format("None of the SmartContextLoader candidates %s "
|
||||
+ "was able to generate defaults for context configuration [%s].", candidates, configAttributes));
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
|
||||
if (configAttributes.hasResources()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("SmartContextLoader candidate %s "
|
||||
+ "generated defaults for context configuration [%s].", loader, configAttributes));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If any loader claims to generate defaults but none actually did,
|
||||
// throw an exception.
|
||||
if (!configAttributes.hasResources()) {
|
||||
throw new IllegalStateException(
|
||||
String.format("None of the SmartContextLoader candidates %s "
|
||||
+ "was able to generate defaults for context configuration [%s].", candidates,
|
||||
configAttributes));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,11 +16,21 @@
|
|||
|
||||
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;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfigurationAttributes;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DelegatingSmartContextLoader}.
|
||||
|
|
@ -36,6 +46,10 @@ public class DelegatingSmartContextLoaderTests {
|
|||
private final DelegatingSmartContextLoader loader = new DelegatingSmartContextLoader();
|
||||
|
||||
|
||||
private static void assertEmpty(Object[] array) {
|
||||
assertTrue(ObjectUtils.isEmpty(array));
|
||||
}
|
||||
|
||||
// --- SmartContextLoader --------------------------------------------------
|
||||
|
||||
@Test
|
||||
|
|
@ -43,9 +57,49 @@ public class DelegatingSmartContextLoaderTests {
|
|||
assertTrue(loader.generatesDefaults());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void processContextConfigurationWithoutLocationsAndConfigurationClassesForBogusTestClass() {
|
||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(getClass(),
|
||||
EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, ContextLoader.class);
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processContextConfiguration() {
|
||||
// TODO test processContextConfiguration().
|
||||
public void processContextConfigurationWithDefaultXmlConfigGeneration() {
|
||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(XmlTestCase.class,
|
||||
EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, ContextLoader.class);
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
assertEquals(1, configAttributes.getLocations().length);
|
||||
assertEmpty(configAttributes.getClasses());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processContextConfigurationWithDefaultConfigurationClassGeneration() {
|
||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(ConfigClassTestCase.class,
|
||||
EMPTY_STRING_ARRAY, EMPTY_CLASS_ARRAY, true, ContextLoader.class);
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
assertEquals(1, configAttributes.getClasses().length);
|
||||
assertEmpty(configAttributes.getLocations());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processContextConfigurationWithLocation() {
|
||||
String[] locations = new String[] { "classpath:/foo.xml" };
|
||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(getClass(), locations,
|
||||
EMPTY_CLASS_ARRAY, true, ContextLoader.class);
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
assertArrayEquals(locations, configAttributes.getLocations());
|
||||
assertEmpty(configAttributes.getClasses());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void processContextConfigurationWithConfigurationClass() {
|
||||
Class<?>[] classes = new Class<?>[] { getClass() };
|
||||
ContextConfigurationAttributes configAttributes = new ContextConfigurationAttributes(getClass(),
|
||||
EMPTY_STRING_ARRAY, classes, true, ContextLoader.class);
|
||||
loader.processContextConfiguration(configAttributes);
|
||||
assertArrayEquals(classes, configAttributes.getClasses());
|
||||
assertEmpty(configAttributes.getLocations());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
|
|
@ -95,9 +149,29 @@ public class DelegatingSmartContextLoaderTests {
|
|||
loader.loadContext(mergedConfig);
|
||||
}
|
||||
|
||||
private void assertApplicationContextLoadsAndContainsFooString(MergedContextConfiguration mergedConfig)
|
||||
throws Exception {
|
||||
ApplicationContext applicationContext = loader.loadContext(mergedConfig);
|
||||
assertNotNull(applicationContext);
|
||||
assertEquals("foo", applicationContext.getBean(String.class));
|
||||
assertTrue(applicationContext instanceof ConfigurableApplicationContext);
|
||||
((ConfigurableApplicationContext) applicationContext).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadContext() {
|
||||
// TODO test loadContext().
|
||||
public void loadContextWithXmlConfig() throws Exception {
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(
|
||||
XmlTestCase.class,
|
||||
new String[] { "classpath:/org/springframework/test/context/support/DelegatingSmartContextLoaderTests$XmlTestCase-context.xml" },
|
||||
EMPTY_CLASS_ARRAY, EMPTY_STRING_ARRAY, loader);
|
||||
assertApplicationContextLoadsAndContainsFooString(mergedConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loadContextWithConfigurationClass() throws Exception {
|
||||
MergedContextConfiguration mergedConfig = new MergedContextConfiguration(ConfigClassTestCase.class,
|
||||
EMPTY_STRING_ARRAY, new Class<?>[] { ConfigClassTestCase.Config.class }, EMPTY_STRING_ARRAY, loader);
|
||||
assertApplicationContextLoadsAndContainsFooString(mergedConfig);
|
||||
}
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
|
@ -112,4 +186,20 @@ public class DelegatingSmartContextLoaderTests {
|
|||
loader.loadContext(EMPTY_STRING_ARRAY);
|
||||
}
|
||||
|
||||
|
||||
static class XmlTestCase {
|
||||
}
|
||||
|
||||
static class ConfigClassTestCase {
|
||||
|
||||
@Configuration
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
public String foo() {
|
||||
return new String("foo");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
||||
<bean id="foo" class="java.lang.String" c:_="foo" />
|
||||
|
||||
</beans>
|
||||
Loading…
Reference in New Issue