/* * 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.support; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.GenericApplicationContext; import org.springframework.test.context.ContextConfigurationAttributes; import org.springframework.test.context.MergedContextConfiguration; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; /** * Concrete implementation of {@link AbstractGenericContextLoader} that loads * bean definitions from * {@link org.springframework.context.annotation.Configuration configuration classes}. * *
Note: AnnotationConfigContextLoader
supports
* {@link org.springframework.context.annotation.Configuration configuration classes}
* rather than the String-based resource locations defined by the legacy
* {@link org.springframework.test.context.ContextLoader ContextLoader} API. Thus,
* although AnnotationConfigContextLoader
extends
* AbstractGenericContextLoader
, AnnotationConfigContextLoader
* does not support any String-based methods defined by
* AbstractContextLoader
or AbstractGenericContextLoader
.
* Consequently, AnnotationConfigContextLoader
should chiefly be
* considered a {@link org.springframework.test.context.SmartContextLoader SmartContextLoader}
* rather than a {@link org.springframework.test.context.ContextLoader ContextLoader}.
*
* @author Sam Brannen
* @since 3.1
* @see #generateDefaultConfigurationClasses
* @see #loadBeanDefinitions
*/
public class AnnotationConfigContextLoader extends AbstractGenericContextLoader {
private static final Log logger = LogFactory.getLog(AnnotationConfigContextLoader.class);
// --- SmartContextLoader -----------------------------------------------
/**
* TODO Document overridden processContextConfiguration().
*
* @see org.springframework.test.context.SmartContextLoader#processContextConfiguration
* @see #generatesDefaults
* @see #generateDefaultConfigurationClasses
*/
public void processContextConfiguration(ContextConfigurationAttributes configAttributes) {
if (ObjectUtils.isEmpty(configAttributes.getClasses()) && generatesDefaults()) {
Class>[] defaultConfigClasses = generateDefaultConfigurationClasses(configAttributes.getDeclaringClass());
configAttributes.setClasses(defaultConfigClasses);
}
}
// --- AnnotationConfigContextLoader ---------------------------------------
private boolean isStaticNonPrivateAndNonFinal(Class> clazz) {
Assert.notNull(clazz, "Class must not be null");
int modifiers = clazz.getModifiers();
return (Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers) && !Modifier.isFinal(modifiers));
}
/**
* Determine if the supplied {@link Class} meets the criteria for being considered
* as a default configuration class candidate.
*
Specifically, such candidates: *
null
private
final
static
true
if the supplied class meets the candidate criteria
*/
private boolean isDefaultConfigurationClassCandidate(Class> clazz) {
return clazz != null && isStaticNonPrivateAndNonFinal(clazz) && clazz.isAnnotationPresent(Configuration.class);
}
/**
* TODO Document generateDefaultConfigurationClasses().
*/
protected Class>[] generateDefaultConfigurationClasses(Class> declaringClass) {
Assert.notNull(declaringClass, "Declaring class must not be null");
ListAnnotationConfigContextLoader
should be used as a
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
* Consequently, this method is not supported.
*
* @see AbstractContextLoader#modifyLocations
* @throws UnsupportedOperationException
*/
@Override
protected String[] modifyLocations(Class> clazz, String... locations) {
throw new UnsupportedOperationException(
"AnnotationConfigContextLoader does not support the modifyLocations(Class, String...) method");
}
/**
* AnnotationConfigContextLoader
should be used as a
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
* Consequently, this method is not supported.
*
* @see AbstractContextLoader#generateDefaultLocations
* @throws UnsupportedOperationException
*/
@Override
protected String[] generateDefaultLocations(Class> clazz) {
throw new UnsupportedOperationException(
"AnnotationConfigContextLoader does not support the generateDefaultLocations(Class) method");
}
/**
* AnnotationConfigContextLoader
should be used as a
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
* Consequently, this method is not supported.
*
* @see AbstractContextLoader#getResourceSuffix
* @throws UnsupportedOperationException
*/
@Override
protected String getResourceSuffix() {
throw new UnsupportedOperationException(
"AnnotationConfigContextLoader does not support the getResourceSuffix() method");
}
// --- AbstractGenericContextLoader ----------------------------------------
/**
* Register {@link org.springframework.context.annotation.Configuration configuration classes}
* in the supplied {@link GenericApplicationContext context} from the classes
* in the supplied {@link MergedContextConfiguration}.
*
* Each class must represent an annotated configuration class or component. An * {@link AnnotatedBeanDefinitionReader} is used to register the appropriate * bean definitions. * *
Note that this method does not call {@link #createBeanDefinitionReader}
* since AnnotatedBeanDefinitionReader
is not an instance of
* {@link BeanDefinitionReader}.
*
* @param context the context in which the configuration classes should be registered
* @param mergedConfig the merged configuration from which the classes should be retrieved
* @see AbstractGenericContextLoader#loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(GenericApplicationContext context, MergedContextConfiguration mergedConfig) {
Class>[] configClasses = mergedConfig.getClasses();
if (logger.isDebugEnabled()) {
logger.debug("Registering configuration classes: " + ObjectUtils.nullSafeToString(configClasses));
}
new AnnotatedBeanDefinitionReader(context).register(configClasses);
}
/**
* AnnotationConfigContextLoader
should be used as a
* {@link org.springframework.test.context.SmartContextLoader SmartContextLoader},
* not as a legacy {@link org.springframework.test.context.ContextLoader ContextLoader}.
* Consequently, this method is not supported.
*
* @see #loadBeanDefinitions
* @see AbstractGenericContextLoader#createBeanDefinitionReader
* @throws UnsupportedOperationException
*/
@Override
protected BeanDefinitionReader createBeanDefinitionReader(GenericApplicationContext context) {
throw new UnsupportedOperationException(
"AnnotationConfigContextLoader does not support the createBeanDefinitionReader(GenericApplicationContext) method");
}
}