Browse Source

Register all packages where @EnableAutoConfiguration is used

Previously, when @EnableAutoConfiguration was used in multiple packages,
the last @EnableAutoConfiguration that was processed would
win and only its package would be stored as an auto-configuration
package.

This commit updates AutoConfigurationPackages to allow multiple package
name registrations. AutoConfigurationPackages.set(…) has been altered to
augment the constructor arguments of the BeanDefinition registered for
the initial call to the method so that the packages handed to the method
call will be added to the bean definition and not replace the previous
ones. The method has been renamed register(…) to reflect the changed
behavior.

Closes gh-1994
pull/2009/head
Oliver Gierke 11 years ago committed by Andy Wilkinson
parent
commit
123b90fa64
  1. 57
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java
  2. 31
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationPackagesTests.java
  3. 2
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/TestAutoConfigurationPackageRegistrar.java
  4. 27
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packages/one/FirstConfiguration.java
  5. 27
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packages/two/SecondConfiguration.java

57
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.boot.autoconfigure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.logging.Log;
@ -24,6 +25,8 @@ import org.apache.commons.logging.LogFactory; @@ -24,6 +25,8 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
@ -39,6 +42,7 @@ import org.springframework.util.StringUtils; @@ -39,6 +42,7 @@ import org.springframework.util.StringUtils;
*
* @author Phillip Webb
* @author Dave Syer
* @author Oliver Gierke
*/
public abstract class AutoConfigurationPackages {
@ -75,21 +79,46 @@ public abstract class AutoConfigurationPackages { @@ -75,21 +79,46 @@ public abstract class AutoConfigurationPackages {
}
/**
* Programmatically set the auto-configuration package names. You can use this method
* to manually define the base packages that will be used for a given
* {@link BeanDefinitionRegistry}. Generally it's recommended that you don't call this
* method directly, but instead rely on the default convention where the package name
* is set from your {@code @EnableAutoConfiguration} configuration class.
* Programmatically registers the auto-configuration package names. Subsequent
* invocations will add the given package names to those that have already been
* registered. You can use this method to manually define the base packages that will
* be used for a given {@link BeanDefinitionRegistry}. Generally it's recommended that
* you don't call this method directly, but instead rely on the default convention
* where the package name is set from your {@code @EnableAutoConfiguration}
* configuration class or classes.
* @param registry the bean definition registry
* @param packageNames the pacakge names to set
* @param packageNames the package names to set
*/
public static void set(BeanDefinitionRegistry registry, String... packageNames) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition
.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0,
augmentBasePackages(constructorArguments, packageNames));
}
else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(BasePackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
packageNames);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
private static String[] augmentBasePackages(
ConstructorArgumentValues constructorArguments, String[] packageNames) {
ValueHolder valueHolder = constructorArguments.getIndexedArgumentValue(0,
List.class);
List<String> packages = new ArrayList<String>(
Arrays.asList((String[]) valueHolder.getValue()));
packages.addAll(Arrays.asList(packageNames));
return packages.toArray(new String[packages.size()]);
}
/**
@ -102,7 +131,7 @@ public abstract class AutoConfigurationPackages { @@ -102,7 +131,7 @@ public abstract class AutoConfigurationPackages {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
set(registry, ClassUtils.getPackageName(metadata.getClassName()));
register(registry, ClassUtils.getPackageName(metadata.getClassName()));
}
}

31
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationPackagesTests.java

@ -17,21 +17,28 @@ @@ -17,21 +17,28 @@
package org.springframework.boot.autoconfigure;
import java.util.Collections;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar;
import org.springframework.boot.autoconfigure.packages.one.FirstConfiguration;
import org.springframework.boot.autoconfigure.packages.two.SecondConfiguration;
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.hamcrest.Matchers.hasItems;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link AutoConfigurationPackages}.
*
* @author Phillip Webb
* @author Oliver Gierke
*/
@SuppressWarnings("resource")
public class AutoConfigurationPackagesTests {
@ -57,13 +64,37 @@ public class AutoConfigurationPackagesTests { @@ -57,13 +64,37 @@ public class AutoConfigurationPackagesTests {
AutoConfigurationPackages.get(context.getBeanFactory());
}
@Test
public void detectsMultipleAutoConfigurationPackages() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
FirstConfiguration.class, SecondConfiguration.class);
List<String> packages = AutoConfigurationPackages.get(context.getBeanFactory());
assertThat(
packages,
hasItems(FirstConfiguration.class.getPackage().getName(),
SecondConfiguration.class.getPackage().getName()));
assertThat(packages, hasSize(2));
}
@Configuration
@Import(AutoConfigurationPackages.Registrar.class)
static class ConfigWithRegistrar {
}
@Configuration
static class EmptyConfig {
}
/**
* Test helper to allow {@link Registrar} to be referenced from other packages.
*/
public static class TestRegistrar extends Registrar {
}
}

2
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/TestAutoConfigurationPackageRegistrar.java

@ -39,7 +39,7 @@ public class TestAutoConfigurationPackageRegistrar implements @@ -39,7 +39,7 @@ public class TestAutoConfigurationPackageRegistrar implements
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata
.getAnnotationAttributes(TestAutoConfigurationPackage.class.getName(),
true));
AutoConfigurationPackages.set(registry,
AutoConfigurationPackages.register(registry,
ClassUtils.getPackageName(attributes.getString("value")));
}

27
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packages/one/FirstConfiguration.java

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/*
* 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.packages.one;
import org.springframework.boot.autoconfigure.AutoConfigurationPackagesTests.TestRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(TestRegistrar.class)
public class FirstConfiguration {
}

27
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packages/two/SecondConfiguration.java

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
/*
* 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.packages.two;
import org.springframework.boot.autoconfigure.AutoConfigurationPackagesTests.TestRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(TestRegistrar.class)
public class SecondConfiguration {
}
Loading…
Cancel
Save