Polishing
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -57,7 +57,7 @@ import org.springframework.util.ObjectUtils;
|
||||
* files nor annotated classes and instead declare only {@linkplain
|
||||
* ContextConfiguration#initializers application context initializers}. In such
|
||||
* cases, an attempt will still be made to detect defaults, but their absence will
|
||||
* not result an an exception.
|
||||
* not result in an exception.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.2
|
||||
@@ -78,6 +78,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
*/
|
||||
protected abstract SmartContextLoader getAnnotationConfigLoader();
|
||||
|
||||
|
||||
// --- SmartContextLoader --------------------------------------------------
|
||||
|
||||
private static String name(SmartContextLoader loader) {
|
||||
@@ -94,6 +95,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
|
||||
private static ApplicationContext delegateLoading(SmartContextLoader loader, MergedContextConfiguration mergedConfig)
|
||||
throws Exception {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format("Delegating to %s to load context from %s.", name(loader), mergedConfig));
|
||||
}
|
||||
@@ -103,7 +105,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
private boolean supports(SmartContextLoader loader, MergedContextConfiguration mergedConfig) {
|
||||
if (loader == getAnnotationConfigLoader()) {
|
||||
return ObjectUtils.isEmpty(mergedConfig.getLocations()) && !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return !ObjectUtils.isEmpty(mergedConfig.getLocations()) && ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
}
|
||||
}
|
||||
@@ -111,12 +114,10 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
/**
|
||||
* Delegates to candidate {@code SmartContextLoaders} to process the supplied
|
||||
* {@link ContextConfigurationAttributes}.
|
||||
*
|
||||
* <p>Delegation is based on explicit knowledge of the implementations of the
|
||||
* default loaders for {@link #getXmlLoader() XML configuration files} and
|
||||
* {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
|
||||
* delegation algorithm is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the resource locations or annotated classes in the supplied
|
||||
* {@code ContextConfigurationAttributes} are not empty, the appropriate
|
||||
@@ -131,7 +132,6 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
* If the annotation-based loader detects default configuration
|
||||
* classes, an {@code info} message will be logged.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param configAttributes the context configuration attributes to process
|
||||
* @throws IllegalArgumentException if the supplied configuration attributes are
|
||||
* {@code null}, or if the supplied configuration attributes include both
|
||||
@@ -146,17 +146,19 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
|
||||
Assert.notNull(configAttributes, "configAttributes must not be null");
|
||||
Assert.isTrue(!(configAttributes.hasLocations() && configAttributes.hasClasses()), String.format(
|
||||
"Cannot process locations AND classes for context "
|
||||
+ "configuration %s; configure one or the other, but not both.", configAttributes));
|
||||
"Cannot process locations AND classes for context configuration %s; configure one or the other, but not both.",
|
||||
configAttributes));
|
||||
|
||||
// If the original locations or classes were not empty, there's no
|
||||
// need to bother with default detection checks; just let the
|
||||
// appropriate loader process the configuration.
|
||||
if (configAttributes.hasLocations()) {
|
||||
delegateProcessing(getXmlLoader(), configAttributes);
|
||||
} else if (configAttributes.hasClasses()) {
|
||||
}
|
||||
else if (configAttributes.hasClasses()) {
|
||||
delegateProcessing(getAnnotationConfigLoader(), configAttributes);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
// Else attempt to detect defaults...
|
||||
|
||||
// Let the XML loader process the configuration.
|
||||
@@ -197,15 +199,15 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
// throw an exception.
|
||||
if (!configAttributes.hasResources() && ObjectUtils.isEmpty(configAttributes.getInitializers())) {
|
||||
throw new IllegalStateException(String.format(
|
||||
"Neither %s nor %s was able to detect defaults, and no ApplicationContextInitializers "
|
||||
+ "were declared for context configuration %s", name(getXmlLoader()),
|
||||
"Neither %s nor %s was able to detect defaults, and no ApplicationContextInitializers " +
|
||||
"were declared for context configuration %s", name(getXmlLoader()),
|
||||
name(getAnnotationConfigLoader()), configAttributes));
|
||||
}
|
||||
|
||||
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.",
|
||||
"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);
|
||||
@@ -216,12 +218,10 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
/**
|
||||
* Delegates to an appropriate candidate {@code SmartContextLoader} to load
|
||||
* an {@link ApplicationContext}.
|
||||
*
|
||||
* <p>Delegation is based on explicit knowledge of the implementations of the
|
||||
* default loaders for {@link #getXmlLoader() XML configuration files} and
|
||||
* {@link #getAnnotationConfigLoader() annotated classes}. Specifically, the
|
||||
* delegation algorithm is as follows:
|
||||
*
|
||||
* <ul>
|
||||
* <li>If the resource locations in the supplied {@code MergedContextConfiguration}
|
||||
* are not empty and the annotated classes are empty,
|
||||
@@ -230,7 +230,6 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
* are not empty and the resource locations are empty,
|
||||
* the annotation-based loader will load the {@code ApplicationContext}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param mergedConfig the merged context configuration to use to load the application context
|
||||
* @throws IllegalArgumentException if the supplied merged configuration is {@code null}
|
||||
* @throws IllegalStateException if neither candidate loader is capable of loading an
|
||||
@@ -238,7 +237,6 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
*/
|
||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
Assert.notNull(mergedConfig, "mergedConfig must not be null");
|
||||
|
||||
List<SmartContextLoader> candidates = Arrays.asList(getXmlLoader(), getAnnotationConfigLoader());
|
||||
|
||||
for (SmartContextLoader loader : candidates) {
|
||||
@@ -260,6 +258,7 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
name(getAnnotationConfigLoader()), mergedConfig));
|
||||
}
|
||||
|
||||
|
||||
// --- ContextLoader -------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -269,8 +268,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public final String[] processLocations(Class<?> clazz, String... locations) {
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
|
||||
+ "Call processContextConfiguration(ContextConfigurationAttributes) instead.");
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. " +
|
||||
"Call processContextConfiguration(ContextConfigurationAttributes) instead.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,8 +279,8 @@ public abstract class AbstractDelegatingSmartContextLoader implements SmartConte
|
||||
* @throws UnsupportedOperationException
|
||||
*/
|
||||
public final ApplicationContext loadContext(String... locations) throws Exception {
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. "
|
||||
+ "Call loadContext(MergedContextConfiguration) instead.");
|
||||
throw new UnsupportedOperationException("DelegatingSmartContextLoaders do not support the ContextLoader SPI. " +
|
||||
"Call loadContext(MergedContextConfiguration) instead.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,6 +22,7 @@ import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -38,8 +39,22 @@ public abstract class AnnotationConfigContextLoaderUtils {
|
||||
private static final Log logger = LogFactory.getLog(AnnotationConfigContextLoaderUtils.class);
|
||||
|
||||
|
||||
private AnnotationConfigContextLoaderUtils() {
|
||||
/* no-op */
|
||||
/**
|
||||
* Determine if the supplied {@link Class} meets the criteria for being
|
||||
* considered a <em>default configuration class</em> candidate.
|
||||
* <p>Specifically, such candidates:
|
||||
* <ul>
|
||||
* <li>must not be {@code null}</li>
|
||||
* <li>must not be {@code private}</li>
|
||||
* <li>must not be {@code final}</li>
|
||||
* <li>must be {@code static}</li>
|
||||
* <li>must be annotated with {@code @Configuration}</li>
|
||||
* </ul>
|
||||
* @param clazz the class to check
|
||||
* @return {@code true} if the supplied class meets the candidate criteria
|
||||
*/
|
||||
private static boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
|
||||
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
|
||||
}
|
||||
|
||||
private static boolean isStaticNonPrivateAndNonFinal(Class<?> clazz) {
|
||||
@@ -48,59 +63,36 @@ public abstract class AnnotationConfigContextLoaderUtils {
|
||||
return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the supplied {@link Class} meets the criteria for being
|
||||
* considered a <em>default configuration class</em> candidate.
|
||||
*
|
||||
* <p>Specifically, such candidates:
|
||||
*
|
||||
* <ul>
|
||||
* <li>must not be {@code null}</li>
|
||||
* <li>must not be {@code private}</li>
|
||||
* <li>must not be {@code final}</li>
|
||||
* <li>must be {@code static}</li>
|
||||
* <li>must be annotated with {@code @Configuration}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param clazz the class to check
|
||||
* @return {@code true} if the supplied class meets the candidate criteria
|
||||
*/
|
||||
private static boolean isDefaultConfigurationClassCandidate(Class<?> clazz) {
|
||||
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect the default configuration classes for the supplied test class.
|
||||
*
|
||||
* <p>The returned class array will contain all static inner classes of
|
||||
* the supplied class that meet the requirements for {@code @Configuration}
|
||||
* class implementations as specified in the documentation for
|
||||
* {@link Configuration @Configuration}.
|
||||
*
|
||||
* <p>The implementation of this method adheres to the contract defined in the
|
||||
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
|
||||
* SPI. Specifically, this method uses introspection to detect default
|
||||
* configuration classes that comply with the constraints required of
|
||||
* {@code @Configuration} class implementations. If a potential candidate
|
||||
* configuration class does not meet these requirements, this method will log a
|
||||
* warning, and the potential candidate class will be ignored.
|
||||
* debug message, and the potential candidate class will be ignored.
|
||||
* @param declaringClass the test class that declared {@code @ContextConfiguration}
|
||||
* @return an array of default configuration classes, potentially empty but
|
||||
* never {@code null}
|
||||
*/
|
||||
public static Class<?>[] detectDefaultConfigurationClasses(Class<?> declaringClass) {
|
||||
Assert.notNull(declaringClass, "Declaring class must not be null");
|
||||
|
||||
List<Class<?>> configClasses = new ArrayList<Class<?>>();
|
||||
|
||||
for (Class<?> candidate : declaringClass.getDeclaredClasses()) {
|
||||
if (isDefaultConfigurationClassCandidate(candidate)) {
|
||||
configClasses.add(candidate);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(String.format(
|
||||
"Ignoring class [%s]; it must be static, non-private, non-final, and annotated "
|
||||
+ "with @Configuration to be considered a default configuration class.",
|
||||
"Ignoring class [%s]; it must be static, non-private, non-final, and annotated " +
|
||||
"with @Configuration to be considered a default configuration class.",
|
||||
candidate.getName()));
|
||||
}
|
||||
}
|
||||
@@ -108,9 +100,9 @@ public abstract class AnnotationConfigContextLoaderUtils {
|
||||
|
||||
if (configClasses.isEmpty()) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info(String.format("Could not detect default configuration classes for test class [%s]: "
|
||||
+ "%s does not declare any static, non-private, non-final, inner classes "
|
||||
+ "annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
|
||||
logger.info(String.format("Could not detect default configuration classes for test class [%s]: " +
|
||||
"%s does not declare any static, non-private, non-final, inner classes " +
|
||||
"annotated with @Configuration.", declaringClass.getName(), declaringClass.getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user