Don't use @ComponentScan for default packages

Update the 'default' package used for @Entity and Repository scanning
to be the package of the class annotated with @EnableAutoConfiguration
rather than using @ComponentScan.

This allows JPA and Spring Data to be used without requiring component
scanning and also removes the confusion that could arise from reusing
the @ComponentScan annotation, which already has well defined semantics.

Fixes gh-200
This commit is contained in:
Phillip Webb 2014-01-16 22:49:32 -08:00
parent 6c255e5785
commit f103a976f8
17 changed files with 282 additions and 386 deletions

View File

@ -0,0 +1,104 @@
/*
* Copyright 2012-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.
* 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.boot.autoconfigure;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
/**
* Class for storing auto-configuration packages for reference later (e.g. by JPA entity
* scanner).
*
* @author Phillip Webb
* @author Dave Syer
*/
public abstract class AutoConfigurationPackages {
private static final String BEAN = AutoConfigurationPackages.class.getName();
/**
* Return the auto-configuration base packages for the given bean factory
* @param beanFactory the source bean factory
* @return a list of auto-configuration packages
* @throws IllegalStateException if auto-configuration is not enabled
*/
public static List<String> get(BeanFactory beanFactory) {
// Currently we only store a single base package, but we return a list to
// allow this to change in the future if needed
try {
return Collections.singletonList(beanFactory.getBean(BEAN, BasePackage.class)
.toString());
}
catch (NoSuchBeanDefinitionException ex) {
throw new IllegalStateException(
"Unable to retrieve @EnableAutoConfiguration base packages");
}
}
static void set(BeanDefinitionRegistry registry, String packageName) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackage.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
packageName);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
set(registry,
ClassUtils.getPackageName(importingClassMetadata.getClassName()));
}
}
/**
* Holder for the base package.
*/
final static class BasePackage {
private final String name;
public BasePackage(String name) {
this.name = name;
}
@Override
public String toString() {
return this.name;
}
}
}

View File

@ -1,71 +0,0 @@
/*
* Copyright 2012-2013 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.boot.autoconfigure;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
/**
* Convenience class for storing base packages during component scan, for reference later
* (e.g. by JPA entity scanner).
*
* @author Phillip Webb
* @author Dave Syer
*/
public abstract class AutoConfigurationUtils {
private static final String BASE_PACKAGES_BEAN = AutoConfigurationUtils.class
.getName() + ".basePackages";
private static Set<String> EXCLUDED_PACKAGES;
static {
Set<String> exclude = new HashSet<String>();
exclude.add("org.springframework.data.rest.webmvc");
EXCLUDED_PACKAGES = Collections.unmodifiableSet(exclude);
}
@SuppressWarnings("unchecked")
public static List<String> getBasePackages(BeanFactory beanFactory) {
try {
return beanFactory.getBean(BASE_PACKAGES_BEAN, List.class);
}
catch (NoSuchBeanDefinitionException ex) {
return Collections.emptyList();
}
}
public static void storeBasePackages(ConfigurableListableBeanFactory beanFactory,
List<String> basePackages) {
if (!beanFactory.containsBean(BASE_PACKAGES_BEAN)) {
beanFactory.registerSingleton(BASE_PACKAGES_BEAN, new ArrayList<String>());
}
List<String> storePackages = getBasePackages(beanFactory);
for (String basePackage : basePackages) {
if (!EXCLUDED_PACKAGES.contains(basePackage)
&& !storePackages.contains(basePackage)) {
storePackages.add(basePackage);
}
}
}
}

View File

@ -1,156 +0,0 @@
/*
* Copyright 2012-2013 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.boot.autoconfigure;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Helper to detect a component scan declared in the enclosing context (normally on a
* {@code @Configuration} class). Once the component scan is detected, the base packages
* are stored for retrieval later.
*
* @author Dave Syer
* @author Phillip Webb
* @see AutoConfigurationUtils
*/
public class ComponentScanDetector implements ImportBeanDefinitionRegistrar,
BeanFactoryAware {
private final Log logger = LogFactory.getLog(getClass());
private BeanFactory beanFactory;
private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
final BeanDefinitionRegistry registry) {
storeComponentScanBasePackages();
}
private void storeComponentScanBasePackages() {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
storeComponentScanBasePackages((ConfigurableListableBeanFactory) this.beanFactory);
}
else {
if (this.logger.isWarnEnabled()) {
this.logger
.warn("Unable to read @ComponentScan annotations for auto-configure");
}
}
}
private void storeComponentScanBasePackages(
ConfigurableListableBeanFactory beanFactory) {
List<String> basePackages = new ArrayList<String>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
String[] basePackagesAttribute = (String[]) beanDefinition
.getAttribute("componentScanBasePackages");
if (basePackagesAttribute != null) {
basePackages.addAll(Arrays.asList(basePackagesAttribute));
}
AnnotationMetadata metadata = getMetadata(beanDefinition);
basePackages.addAll(getBasePackages(metadata));
}
AutoConfigurationUtils.storeBasePackages(beanFactory, basePackages);
}
private AnnotationMetadata getMetadata(BeanDefinition beanDefinition) {
if (beanDefinition instanceof AbstractBeanDefinition
&& ((AbstractBeanDefinition) beanDefinition).hasBeanClass()) {
Class<?> beanClass = ((AbstractBeanDefinition) beanDefinition).getBeanClass();
if (Enhancer.isEnhanced(beanClass)) {
beanClass = beanClass.getSuperclass();
}
return new StandardAnnotationMetadata(beanClass, true);
}
String className = beanDefinition.getBeanClassName();
if (className != null) {
try {
MetadataReader metadataReader = this.metadataReaderFactory
.getMetadataReader(className);
return metadataReader.getAnnotationMetadata();
}
catch (IOException ex) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(
"Could not find class file for introspecting @ComponentScan classes: "
+ className, ex);
}
}
}
return null;
}
private List<String> getBasePackages(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes
.fromMap((metadata == null ? null : metadata.getAnnotationAttributes(
ComponentScan.class.getName(), true)));
if (attributes != null) {
List<String> basePackages = new ArrayList<String>();
addAllHavingText(basePackages, attributes.getStringArray("value"));
addAllHavingText(basePackages, attributes.getStringArray("basePackages"));
for (String packageClass : attributes.getStringArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(packageClass));
}
if (basePackages.isEmpty()) {
basePackages.add(ClassUtils.getPackageName(metadata.getClassName()));
}
return basePackages;
}
return Collections.emptyList();
}
private void addAllHavingText(List<String> list, String[] strings) {
for (String s : strings) {
if (StringUtils.hasText(s)) {
list.add(s);
}
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -34,12 +34,11 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
/**
* Enable auto-configuration of the Spring Application Context, attempting to guess and
* configure beans that you are likely to need.
*
* Auto-configuration classes are usually applied based on your classpath and what beans
* you have defined. For example, If you have {@code tomat-embedded.jar} on your classpath
* you are likely to want a {@link TomcatEmbeddedServletContainerFactory} (unless you have
* defined your own {@link EmbeddedServletContainerFactory} bean).
* configure beans that you are likely to need. Auto-configuration classes are usually
* applied based on your classpath and what beans you have defined. For example, If you
* have {@code tomat-embedded.jar} on your classpath you are likely to want a
* {@link TomcatEmbeddedServletContainerFactory} (unless you have defined your own
* {@link EmbeddedServletContainerFactory} bean).
*
* <p>
* Auto-configuration tries to be as intelligent as possible and will back-away as you
@ -48,6 +47,13 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
* user-defined beans have been registered.
*
* <p>
* The package of the class that is annotated with {@code @EnableAutoConfiguration} has
* specific significance and is often used as a 'default'. For example, it will be used
* when scanning for {@code @Entity} classes. It is generally recommended that you place
* {@code @EnableAutoConfiguration} in a root package so that all sub-packages and classes
* can be searched.
*
* <p>
* Auto-configuration classes are regular Spring {@link Configuration} beans. They are
* located using the {@link SpringFactoriesLoader} mechanism (keyed against this class).
* Generally auto-configuration beans are {@link Conditional @Conditional} beans (most
@ -63,7 +69,8 @@ import org.springframework.core.io.support.SpringFactoriesLoader;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EnableAutoConfigurationImportSelector.class)
@Import({ EnableAutoConfigurationImportSelector.class,
AutoConfigurationPackages.Registrar.class })
public @interface EnableAutoConfiguration {
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -66,9 +66,6 @@ class EnableAutoConfigurationImportSelector implements DeferredImportSelector,
factories = new AutoConfigurationSorter(this.resourceLoader)
.getInPriorityOrder(factories);
// Always add the ComponentScanDetector as the first in the list
factories.add(0, ComponentScanDetector.class.getName());
return factories.toArray(new String[factories.size()]);
}
catch (IOException ex) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -18,17 +18,14 @@ package org.springframework.boot.autoconfigure.data;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.AutoConfigurationUtils;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.env.Environment;
@ -54,9 +51,6 @@ public abstract class AbstractRepositoryConfigurationSourceSupport implements
BeanFactoryAware, ImportBeanDefinitionRegistrar, BeanClassLoaderAware,
EnvironmentAware {
private static Log logger = LogFactory
.getLog(AbstractRepositoryConfigurationSourceSupport.class);
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
@ -108,13 +102,7 @@ public abstract class AbstractRepositoryConfigurationSourceSupport implements
}
protected Iterable<String> getBasePackages() {
List<String> basePackages = AutoConfigurationUtils
.getBasePackages(this.beanFactory);
if (basePackages.isEmpty()) {
logger.info("Unable to find repository base packages. If you need Repositories please define "
+ "a @ComponentScan annotation or else disable *RepositoriesAutoConfiguration");
}
return basePackages;
return AutoConfigurationPackages.get(this.beanFactory);
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -24,7 +24,7 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigurationUtils;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@ -42,7 +42,6 @@ import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
import org.springframework.orm.jpa.vendor.Database;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@ -109,11 +108,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware, Environm
}
protected String[] getPackagesToScan() {
List<String> basePackages = AutoConfigurationUtils
.getBasePackages(this.beanFactory);
Assert.notEmpty(basePackages,
"Unable to find JPA packages to scan, please define "
+ "a @ComponentScan annotation or disable JpaAutoConfiguration");
List<String> basePackages = AutoConfigurationPackages.get(this.beanFactory);
return basePackages.toArray(new String[basePackages.size()]);
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 2012-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.
* 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.boot.autoconfigure;
import java.util.Collections;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link AutoConfigurationPackages}.
*
* @author Phillip Webb
*/
@SuppressWarnings("resource")
public class AutoConfigurationPackagesTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void setAndGet() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConfigWithRegistrar.class);
assertThat(AutoConfigurationPackages.get(context.getBeanFactory()),
equalTo(Collections.singletonList(getClass().getPackage().getName())));
}
@Test
public void getWithoutSet() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
EmptyConfig.class);
this.thrown.expect(IllegalStateException.class);
this.thrown
.expectMessage("Unable to retrieve @EnableAutoConfiguration base packages");
AutoConfigurationPackages.get(context.getBeanFactory());
}
@Configuration
@Import(AutoConfigurationPackages.Registrar.class)
static class ConfigWithRegistrar {
}
@Configuration
static class EmptyConfig {
}
}

View File

@ -1,71 +0,0 @@
/*
* Copyright 2012-2013 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.boot.autoconfigure;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link AutoConfigurationUtils}.
*
* @author Phillip Webb
*/
public class AutoConfigurationUtilsTests {
private ConfigurableListableBeanFactory beanFactory;
@Before
public void setup() {
this.beanFactory = new DefaultListableBeanFactory();
}
@Test
public void storeAndGetBasePackages() throws Exception {
List<String> packageList = Arrays.asList("com.mycorp.test1", "com.mycorp.test2");
AutoConfigurationUtils.storeBasePackages(this.beanFactory, packageList);
List<String> actual = AutoConfigurationUtils.getBasePackages(this.beanFactory);
assertThat(actual, equalTo(packageList));
}
@Test
public void doubleAdd() throws Exception {
List<String> list1 = Arrays.asList("com.mycorp.test1", "com.mycorp.test2");
List<String> list2 = Arrays.asList("com.mycorp.test2", "com.mycorp.test3");
AutoConfigurationUtils.storeBasePackages(this.beanFactory, list1);
AutoConfigurationUtils.storeBasePackages(this.beanFactory, list2);
List<String> actual = AutoConfigurationUtils.getBasePackages(this.beanFactory);
assertThat(actual, equalTo(Arrays.asList("com.mycorp.test1", "com.mycorp.test2",
"com.mycorp.test3")));
}
@Test
public void excludedPackages() throws Exception {
List<String> packageList = Arrays.asList("com.mycorp.test1",
"org.springframework.data.rest.webmvc");
AutoConfigurationUtils.storeBasePackages(this.beanFactory, packageList);
List<String> actual = AutoConfigurationUtils.getBasePackages(this.beanFactory);
assertThat(actual, equalTo(Arrays.asList("com.mycorp.test1")));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -16,15 +16,26 @@
package org.springframework.boot.autoconfigure;
import org.springframework.boot.autoconfigure.ComponentScanDetector;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Simple configuration to import {@link ComponentScanDetector} for tests.
* Test annotation to configure the {@link AutoConfigurationPackages} to an arbitrary
* value.
*
* @author Phillip Webb
*/
@Import(ComponentScanDetector.class)
public class ComponentScanDetectorConfiguration {
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TestAutoConfigurationPackageRegistrar.class)
public @interface TestAutoConfigurationPackage {
Class<?> value();
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2012-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.
* 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.boot.autoconfigure;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package for tests.
*
* @author Phillip Webb
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class TestAutoConfigurationPackageRegistrar implements
ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata
.getAnnotationAttributes(TestAutoConfigurationPackage.class.getName(),
true));
AutoConfigurationPackages.set(registry,
ClassUtils.getPackageName(attributes.getString("value")));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -39,7 +39,7 @@ import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.ComponentScanDetectorConfiguration;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
@ -47,7 +47,6 @@ import org.springframework.boot.autoconfigure.orm.jpa.test.City;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;
@ -149,7 +148,6 @@ public class BatchAutoConfigurationTests {
// The order is very important here: DataSource -> Hibernate -> Batch
this.context.register(TestConfiguration.class,
EmbeddedDataSourceConfiguration.class,
ComponentScanDetectorConfiguration.class,
HibernateJpaAutoConfiguration.class, BatchAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
@ -168,7 +166,7 @@ public class BatchAutoConfigurationTests {
}
@EnableBatchProcessing
@ComponentScan(basePackageClasses = City.class)
@TestAutoConfigurationPackage(City.class)
protected static class TestConfiguration {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -19,14 +19,13 @@ package org.springframework.boot.autoconfigure.data;
import javax.persistence.EntityManagerFactory;
import org.junit.Test;
import org.springframework.boot.autoconfigure.ComponentScanDetectorConfiguration;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.jpa.City;
import org.springframework.boot.autoconfigure.data.jpa.CityRepository;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.PlatformTransactionManager;
@ -46,7 +45,6 @@ public class JpaRepositoriesAutoConfigurationTests {
public void testDefaultRepositoryConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(TestConfiguration.class,
ComponentScanDetectorConfiguration.class,
EmbeddedDataSourceConfiguration.class,
HibernateJpaAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
@ -61,7 +59,6 @@ public class JpaRepositoriesAutoConfigurationTests {
public void testOverrideRepositoryConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(CustomConfiguration.class,
ComponentScanDetectorConfiguration.class,
EmbeddedDataSourceConfiguration.class,
HibernateJpaAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
@ -74,14 +71,14 @@ public class JpaRepositoriesAutoConfigurationTests {
}
@Configuration
@ComponentScan(basePackageClasses = City.class)
@TestAutoConfigurationPackage(City.class)
protected static class TestConfiguration {
}
@Configuration
@EnableJpaRepositories(basePackageClasses = org.springframework.boot.autoconfigure.data.alt.CityRepository.class)
@ComponentScan(basePackageClasses = City.class)
@TestAutoConfigurationPackage(City.class)
protected static class CustomConfiguration {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -17,15 +17,13 @@
package org.springframework.boot.autoconfigure.data;
import org.junit.Test;
import org.springframework.boot.autoconfigure.ComponentScanDetector;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.jpa.City;
import org.springframework.boot.autoconfigure.data.jpa.CityRepository;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.web.PageableHandlerMethodArgumentResolver;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.mock.web.MockServletContext;
@ -59,10 +57,7 @@ public class JpaWebAutoConfigurationTests {
}
@Configuration
@ComponentScan(basePackageClasses = City.class)
// These is usually added by @EnableAutoConfiguration but have to be added as
// annotations if not using that feature
@Import(ComponentScanDetector.class)
@TestAutoConfigurationPackage(City.class)
@EnableWebMvc
protected static class TestConfiguration {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -17,12 +17,11 @@
package org.springframework.boot.autoconfigure.data;
import org.junit.Test;
import org.springframework.boot.autoconfigure.ComponentScanDetectorConfiguration;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.City;
import org.springframework.boot.autoconfigure.data.mongo.CityRepository;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.mongodb.Mongo;
@ -42,7 +41,6 @@ public class MongoRepositoriesAutoConfigurationTests {
public void testDefaultRepositoryConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(TestConfiguration.class,
ComponentScanDetectorConfiguration.class,
MongoRepositoriesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
@ -54,7 +52,6 @@ public class MongoRepositoriesAutoConfigurationTests {
public void testNoRepositoryConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(EmptyConfiguration.class,
ComponentScanDetectorConfiguration.class,
MongoRepositoriesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
@ -62,12 +59,13 @@ public class MongoRepositoriesAutoConfigurationTests {
}
@Configuration
@ComponentScan(basePackageClasses = City.class)
@TestAutoConfigurationPackage(City.class)
protected static class TestConfiguration {
}
@Configuration
@TestAutoConfigurationPackage(MongoRepositoriesAutoConfigurationTests.class)
protected static class EmptyConfiguration {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -23,7 +23,7 @@ import javax.sql.DataSource;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.autoconfigure.ComponentScanDetectorConfiguration;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration;
@ -32,7 +32,6 @@ import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
@ -86,9 +85,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
@Test
public void testOpenEntityManagerInViewInterceptorCreated() throws Exception {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(TestConfiguration.class,
ComponentScanDetectorConfiguration.class,
EmbeddedDataSourceConfiguration.class,
context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass());
context.refresh();
assertNotNull(context.getBean(OpenEntityManagerInViewInterceptor.class));
@ -100,7 +97,6 @@ public abstract class AbstractJpaAutoConfigurationTests {
throws Exception {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(TestFilterConfiguration.class,
ComponentScanDetectorConfiguration.class,
EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass());
context.refresh();
@ -113,9 +109,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
throws Exception {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "spring.jpa.open_in_view:false");
context.register(TestConfiguration.class,
ComponentScanDetectorConfiguration.class,
EmbeddedDataSourceConfiguration.class,
context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass());
context.refresh();
assertEquals(0, getInterceptorBeans(context).length);
@ -159,9 +153,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
}
protected void setupTestConfiguration(Class<?> configClass) {
this.context.register(configClass, ComponentScanDetectorConfiguration.class,
EmbeddedDataSourceConfiguration.class,
this.context.register(configClass, EmbeddedDataSourceConfiguration.class,
PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass());
}
@ -170,13 +162,13 @@ public abstract class AbstractJpaAutoConfigurationTests {
}
@Configuration
@ComponentScan(basePackageClasses = { City.class })
@TestAutoConfigurationPackage(City.class)
protected static class TestConfiguration {
}
@Configuration
@ComponentScan(basePackageClasses = { City.class })
@TestAutoConfigurationPackage(City.class)
protected static class TestFilterConfiguration {
@Bean
@ -204,7 +196,7 @@ public abstract class AbstractJpaAutoConfigurationTests {
}
@Configuration
@ComponentScan(basePackageClasses = { City.class })
@TestAutoConfigurationPackage(City.class)
protected static class TestConfigurationWithTransactionManager {
@Bean

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-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.
@ -19,8 +19,8 @@ package org.springframework.boot.autoconfigure.security;
import org.junit.Test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationBeforeRefreshEvent;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.AutoConfigurationReportLoggingInitializer;
import org.springframework.boot.autoconfigure.ComponentScanDetector;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
@ -28,9 +28,7 @@ import org.springframework.boot.autoconfigure.orm.jpa.test.City;
import org.springframework.boot.context.listener.LoggingApplicationListener;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.mock.web.MockServletContext;
import org.springframework.orm.jpa.JpaTransactionManager;
@ -130,8 +128,7 @@ public class SecurityAutoConfigurationTests {
}
@Configuration
@ComponentScan(basePackageClasses = { City.class })
@Import(ComponentScanDetector.class)
@TestAutoConfigurationPackage(City.class)
protected static class EntityConfiguration {
}