Polishing

This commit is contained in:
Juergen Hoeller
2014-07-29 10:10:48 +02:00
parent daaeeaa8e2
commit c0a4631fd1
56 changed files with 845 additions and 794 deletions

View File

@@ -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.");
}
}

View File

@@ -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()));
}
}