[SPR-7960][SPR-8386] First draft of SmartContextLoader SPI, MergedContextConfiguration, and ContextConfigurationAttributes.
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* TODO [SPR-8386] Document ContextConfigurationAttributes.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @see ContextConfiguration
|
||||
*/
|
||||
public class ContextConfigurationAttributes {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(ContextConfigurationAttributes.class);
|
||||
|
||||
private final Class<?> declaringClass;
|
||||
|
||||
private final String[] locations;
|
||||
|
||||
private final Class<?>[] classes;
|
||||
|
||||
private final boolean inheritLocations;
|
||||
|
||||
private final Class<? extends ContextLoader> contextLoader;
|
||||
|
||||
|
||||
/**
|
||||
* Resolves resource locations from the {@link ContextConfiguration#locations() locations}
|
||||
* and {@link ContextConfiguration#value() value} attributes of the supplied
|
||||
* {@link ContextConfiguration} annotation.
|
||||
*
|
||||
* @throws IllegalStateException if both the locations and value attributes have been declared
|
||||
*/
|
||||
static String[] resolveLocations(Class<?> declaringClass, ContextConfiguration contextConfiguration) {
|
||||
|
||||
String[] locations = contextConfiguration.locations();
|
||||
String[] valueLocations = contextConfiguration.value();
|
||||
|
||||
if (!ObjectUtils.isEmpty(valueLocations) && !ObjectUtils.isEmpty(locations)) {
|
||||
String msg = String.format("Test class [%s] has been configured with @ContextConfiguration's 'value' [%s] "
|
||||
+ "and 'locations' [%s] attributes. Only one declaration of resource "
|
||||
+ "locations is permitted per @ContextConfiguration annotation.", declaringClass,
|
||||
ObjectUtils.nullSafeToString(valueLocations), ObjectUtils.nullSafeToString(locations));
|
||||
logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
else if (!ObjectUtils.isEmpty(valueLocations)) {
|
||||
locations = valueLocations;
|
||||
}
|
||||
|
||||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document ContextConfigurationAttributes constructor.
|
||||
*
|
||||
* @param declaringClass
|
||||
* @param contextConfiguration
|
||||
*/
|
||||
public ContextConfigurationAttributes(Class<?> declaringClass, ContextConfiguration contextConfiguration) {
|
||||
this(declaringClass, resolveLocations(declaringClass, contextConfiguration), contextConfiguration.classes(),
|
||||
contextConfiguration.inheritLocations(), contextConfiguration.loader());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document ContextConfigurationAttributes constructor.
|
||||
*
|
||||
* @param declaringClass
|
||||
* @param locations
|
||||
* @param classes
|
||||
* @param inheritLocations
|
||||
* @param contextLoader
|
||||
*/
|
||||
public ContextConfigurationAttributes(Class<?> declaringClass, String[] locations, Class<?>[] classes,
|
||||
boolean inheritLocations, Class<? extends ContextLoader> contextLoader) {
|
||||
this.declaringClass = declaringClass;
|
||||
this.locations = locations;
|
||||
this.classes = classes;
|
||||
this.inheritLocations = inheritLocations;
|
||||
this.contextLoader = contextLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getDeclaringClass().
|
||||
*/
|
||||
public Class<?> getDeclaringClass() {
|
||||
return this.declaringClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getLocations().
|
||||
*/
|
||||
public String[] getLocations() {
|
||||
return this.locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getClasses().
|
||||
*/
|
||||
public Class<?>[] getClasses() {
|
||||
return this.classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document isInheritLocations().
|
||||
*/
|
||||
public boolean isInheritLocations() {
|
||||
return this.inheritLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getContextLoader().
|
||||
*/
|
||||
public Class<? extends ContextLoader> getContextLoader() {
|
||||
return this.contextLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden toString().
|
||||
*/
|
||||
@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("contextLoader", this.contextLoader)//
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -281,6 +281,69 @@ abstract class ContextLoaderUtils {
|
||||
return StringUtils.toStringArray(activeProfiles);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document resolveContextConfigurationAttributes().
|
||||
*
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
static List<ContextConfigurationAttributes> resolveContextConfigurationAttributes(Class<?> clazz) {
|
||||
Assert.notNull(clazz, "Class must not be null");
|
||||
|
||||
final List<ContextConfigurationAttributes> attributesList = new ArrayList<ContextConfigurationAttributes>();
|
||||
|
||||
Class<ContextConfiguration> annotationType = ContextConfiguration.class;
|
||||
Class<?> declaringClass = AnnotationUtils.findAnnotationDeclaringClass(annotationType, clazz);
|
||||
Assert.notNull(declaringClass, String.format(
|
||||
"Could not find an 'annotation declaring class' for annotation type [%s] and class [%s]", annotationType,
|
||||
clazz));
|
||||
|
||||
while (declaringClass != null) {
|
||||
ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(String.format("Retrieved @ContextConfiguration [%s] for declaring class [%s].",
|
||||
contextConfiguration, declaringClass));
|
||||
}
|
||||
|
||||
ContextConfigurationAttributes attributes = new ContextConfigurationAttributes(declaringClass,
|
||||
contextConfiguration);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Resolved context configuration attributes: " + attributes);
|
||||
}
|
||||
|
||||
attributesList.add(0, attributes);
|
||||
|
||||
declaringClass = contextConfiguration.inheritLocations() ? AnnotationUtils.findAnnotationDeclaringClass(
|
||||
annotationType, declaringClass.getSuperclass()) : null;
|
||||
}
|
||||
|
||||
return attributesList;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document buildMergedContextConfiguration().
|
||||
*
|
||||
* @param testClass
|
||||
* @param defaultContextLoaderClassName
|
||||
* @return
|
||||
*/
|
||||
static MergedContextConfiguration buildMergedContextConfiguration(Class<?> testClass,
|
||||
String defaultContextLoaderClassName) {
|
||||
|
||||
ContextLoader contextLoader = resolveContextLoader(testClass, defaultContextLoaderClassName);
|
||||
|
||||
// TODO Merge locations from List<ContextConfigurationAttributes>
|
||||
String[] locations = resolveContextLocations(contextLoader, testClass);
|
||||
|
||||
// TODO Merge classes from List<ContextConfigurationAttributes>
|
||||
Class<?>[] classes = {};
|
||||
|
||||
String[] activeProfiles = resolveActiveProfiles(testClass);
|
||||
|
||||
return new MergedContextConfiguration(testClass, locations, classes, activeProfiles, contextLoader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Strategy interface for resolving application context resource locations.
|
||||
@@ -317,24 +380,7 @@ abstract class ContextLoaderUtils {
|
||||
* attributes have been declared
|
||||
*/
|
||||
public String[] resolveLocations(ContextConfiguration contextConfiguration, Class<?> declaringClass) {
|
||||
|
||||
String[] locations = contextConfiguration.locations();
|
||||
String[] valueLocations = contextConfiguration.value();
|
||||
|
||||
if (!ObjectUtils.isEmpty(valueLocations) && !ObjectUtils.isEmpty(locations)) {
|
||||
String msg = String.format(
|
||||
"Test class [%s] has been configured with @ContextConfiguration's 'value' [%s] "
|
||||
+ "and 'locations' [%s] attributes. Only one declaration of resource "
|
||||
+ "locations is permitted per @ContextConfiguration annotation.", declaringClass,
|
||||
ObjectUtils.nullSafeToString(valueLocations), ObjectUtils.nullSafeToString(locations));
|
||||
ContextLoaderUtils.logger.error(msg);
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
else if (!ObjectUtils.isEmpty(valueLocations)) {
|
||||
locations = valueLocations;
|
||||
}
|
||||
|
||||
return locations;
|
||||
return ContextConfigurationAttributes.resolveLocations(declaringClass, contextConfiguration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* TODO [SPR-8386] Document MergedContextConfiguration.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
* @see ContextConfiguration
|
||||
* @see ActiveProfiles
|
||||
*/
|
||||
public class MergedContextConfiguration {
|
||||
|
||||
private final Class<?> testClass;
|
||||
|
||||
private final String[] locations;
|
||||
|
||||
private final Class<?>[] classes;
|
||||
|
||||
private final String[] activeProfiles;
|
||||
|
||||
private final ContextLoader contextLoader;
|
||||
|
||||
|
||||
/**
|
||||
* TODO Document MergedContextConfiguration constructor.
|
||||
*
|
||||
* @param testClass
|
||||
* @param locations
|
||||
* @param classes
|
||||
* @param activeProfiles
|
||||
* @param contextLoader
|
||||
*/
|
||||
public MergedContextConfiguration(Class<?> testClass, String[] locations, Class<?>[] classes,
|
||||
String[] activeProfiles, ContextLoader contextLoader) {
|
||||
this.testClass = testClass;
|
||||
this.locations = locations;
|
||||
this.classes = classes;
|
||||
this.activeProfiles = activeProfiles;
|
||||
this.contextLoader = contextLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getTestClass().
|
||||
*/
|
||||
public Class<?> getTestClass() {
|
||||
return this.testClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getLocations().
|
||||
*/
|
||||
public String[] getLocations() {
|
||||
return this.locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getClasses().
|
||||
*/
|
||||
public Class<?>[] getClasses() {
|
||||
return this.classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getActiveProfiles().
|
||||
*/
|
||||
public String[] getActiveProfiles() {
|
||||
return this.activeProfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document getContextLoader().
|
||||
*/
|
||||
public ContextLoader getContextLoader() {
|
||||
return this.contextLoader;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO Document overridden toString().
|
||||
*/
|
||||
@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("contextLoader", this.contextLoader)//
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.context;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* TODO [SPR-8386] Document SmartContextLoader.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface SmartContextLoader extends ContextLoader {
|
||||
|
||||
/**
|
||||
* TODO Document loadContext().
|
||||
*
|
||||
* @param mergedContextConfiguration
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
ApplicationContext loadContext(MergedContextConfiguration mergedContextConfiguration) throws Exception;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user