From 80e0a5b8a58d7261cfdcadbfeece61e9c5b4957f Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Tue, 29 Mar 2011 23:38:37 +0000 Subject: [PATCH] [SPR-6184] Initial draft of the new AnnotationConfigContextLoader. git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4131 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../test/context/TestContext.java | 22 ++- .../AnnotationConfigContextLoader.java | 159 ++++++++++++++++++ ...figSpringJUnit4ClassRunnerAppCtxTests.java | 31 ++++ ...ingJUnit4ClassRunnerAppCtxTestsConfig.java | 62 +++++++ 4 files changed, 273 insertions(+), 1 deletion(-) create mode 100644 org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTestsConfig.java diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java b/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java index 31228dc2417..16fbce2fa8a 100644 --- a/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java +++ b/org.springframework.test/src/main/java/org/springframework/test/context/TestContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2009 the original author or authors. + * 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. @@ -235,6 +235,26 @@ public class TestContext extends AttributeAccessorSupport { Assert.notNull(declaringClass, "Could not find an 'annotation declaring class' for annotation type [" + annotationType + "] and class [" + clazz + "]"); + // TODO [SPR-6184] Implement recursive search for configuration classes. + // This needs to integrate seamlessly (i.e., analogous yet mutually + // exclusive) with the existing locations search. + ContextConfiguration cc = declaringClass.getAnnotation(annotationType); + if (cc != null) { + if (logger.isTraceEnabled()) { + logger.trace("Retrieved @ContextConfiguration [" + cc + "] for declaring class [" + declaringClass + + "]"); + } + + Class[] configClasses = cc.classes(); + + if (!ObjectUtils.isEmpty(configClasses)) { + for (Class configClass : configClasses) { + locationsList.add(configClass.getName()); + } + return locationsList.toArray(new String[locationsList.size()]); + } + } + while (declaringClass != null) { ContextConfiguration contextConfiguration = declaringClass.getAnnotation(annotationType); if (logger.isTraceEnabled()) { diff --git a/org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java b/org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java new file mode 100644 index 00000000000..0553d7f59a7 --- /dev/null +++ b/org.springframework.test/src/main/java/org/springframework/test/context/support/AnnotationConfigContextLoader.java @@ -0,0 +1,159 @@ +/* + * 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.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.AnnotationConfigUtils; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.util.ObjectUtils; + +/** + * TODO Document AnnotationConfigContextLoader. + * + * @author Sam Brannen + * @since 3.1 + */ +public class AnnotationConfigContextLoader extends AbstractContextLoader { + + private static final Log logger = LogFactory.getLog(AnnotationConfigContextLoader.class); + + + /** + * TODO Document loadContext(). + * + * @see org.springframework.test.context.ContextLoader#loadContext(java.lang.String[]) + */ + public ApplicationContext loadContext(String... locations) throws Exception { + if (logger.isDebugEnabled()) { + logger.debug("Creating an AnnotationConfigApplicationContext for " + + ObjectUtils.nullSafeToString(locations)); + } + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + prepareContext(context); + customizeBeanFactory(context.getDefaultListableBeanFactory()); + + List> configClasses = new ArrayList>(); + for (String location : locations) { + final Class clazz = getClass().getClassLoader().loadClass(location); + configClasses.add(clazz); + } + + if (logger.isDebugEnabled()) { + logger.debug("Loading AnnotationConfigApplicationContext from config classes: " + configClasses); + } + + for (Class configClass : configClasses) { + context.register(configClass); + } + + AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + customizeContext(context); + context.refresh(); + context.registerShutdownHook(); + + return context; + } + + /** + * Prepare the {@link GenericApplicationContext} created by this + * ContextLoader. Called before bean definitions are read. + *

+ * The default implementation is empty. Can be overridden in subclasses to + * customize GenericApplicationContext's standard settings. + * + * @param context the context for which the BeanDefinitionReader should be + * created + * @see #loadContext + * @see org.springframework.context.support.GenericApplicationContext#setResourceLoader + * @see org.springframework.context.support.GenericApplicationContext#setId + */ + protected void prepareContext(GenericApplicationContext context) { + } + + /** + * Customize the internal bean factory of the ApplicationContext created by + * this ContextLoader. + *

+ * The default implementation is empty but can be overridden in subclasses + * to customize DefaultListableBeanFactory's standard settings. + * + * @param beanFactory the bean factory created by this ContextLoader + * @see #loadContext + * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowBeanDefinitionOverriding(boolean) + * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowEagerClassLoading(boolean) + * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowCircularReferences(boolean) + * @see org.springframework.beans.factory.support.DefaultListableBeanFactory#setAllowRawInjectionDespiteWrapping(boolean) + */ + protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { + } + + /** + * Customize the {@link GenericApplicationContext} created by this + * ContextLoader after bean definitions have been loaded into the + * context but before the context is refreshed. + *

+ * The default implementation is empty but can be overridden in subclasses + * to customize the application context. + * + * @param context the newly created application context + * @see #loadContext(String...) + */ + protected void customizeContext(GenericApplicationContext context) { + } + + /** + * TODO Document overridden generateDefaultLocations(). + * + * @see org.springframework.test.context.support.AbstractContextLoader#generateDefaultLocations(java.lang.Class) + */ + @Override + protected String[] generateDefaultLocations(Class clazz) { + // TODO Implement generateDefaultLocations(). + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * TODO Document modifyLocations(). + * + * @see org.springframework.test.context.support.AbstractContextLoader#modifyLocations(java.lang.Class, + * java.lang.String[]) + */ + @Override + protected String[] modifyLocations(Class clazz, String... locations) { + // TODO Implement modifyLocations() (?). + return locations; + } + + /** + * TODO Document getResourceSuffix(). + * + * @see org.springframework.test.context.support.AbstractContextLoader#getResourceSuffix() + */ + @Override + protected String getResourceSuffix() { + return "Config"; + } + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java new file mode 100644 index 00000000000..d717edefbde --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests.java @@ -0,0 +1,31 @@ +/* + * 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.junit4; + +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.support.AnnotationConfigContextLoader; + +/** + * TODO [SPR-6184] Document AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests. + * + * @author Sam Brannen + * @since 3.1 + */ +@ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = AnnotationConfigSpringJUnit4ClassRunnerAppCtxTestsConfig.class, inheritLocations = false) +public class AnnotationConfigSpringJUnit4ClassRunnerAppCtxTests extends SpringJUnit4ClassRunnerAppCtxTests { + /* all tests are in the parent class. */ +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTestsConfig.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTestsConfig.java new file mode 100644 index 00000000000..82f9a796ed9 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/AnnotationConfigSpringJUnit4ClassRunnerAppCtxTestsConfig.java @@ -0,0 +1,62 @@ +/* + * 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.junit4; + +import org.springframework.beans.Employee; +import org.springframework.beans.Pet; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * TODO [SPR-6184] Document configuration class. + * + * @author Sam Brannen + * @since 3.1 + */ +@Configuration +public class AnnotationConfigSpringJUnit4ClassRunnerAppCtxTestsConfig { + + @Bean + public Employee employee() { + Employee employee = new Employee(); + employee.setName("John Smith"); + employee.setAge(42); + employee.setCompany("Acme Widgets, Inc."); + return employee; + } + + @Bean + public Pet pet() { + return new Pet("Fido"); + } + + @Bean + public String foo() { + return "Foo"; + } + + @Bean + public String bar() { + return "Bar"; + } + + @Bean + public String quux() { + return "Quux"; + } + +}