Browse Source

Allow base packages to be specified on @AutoConfigurationPackage

Closes gh-19023
pull/21259/head
Andy Wilkinson 6 years ago
parent
commit
d167bb472d
  1. 28
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackage.java
  2. 37
      spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackages.java
  3. 43
      spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationPackagesTests.java
  4. 8
      spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelectorTests.java
  5. 7
      spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/one/FirstConfiguration.java
  6. 7
      spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/two/SecondConfiguration.java

28
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/AutoConfigurationPackage.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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.
@ -26,8 +26,9 @@ import java.lang.annotation.Target; @@ -26,8 +26,9 @@ import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* Indicates that the package containing the annotated class should be registered with
* {@link AutoConfigurationPackages}.
* Registers packages with {@link AutoConfigurationPackages}. When no {@link #basePackages
* base packages} or {@link #basePackageClasses base package classes} are specified, the
* package of the annotated class is registered.
*
* @author Phillip Webb
* @since 1.3.0
@ -40,4 +41,25 @@ import org.springframework.context.annotation.Import; @@ -40,4 +41,25 @@ import org.springframework.context.annotation.Import;
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
/**
* Base packages that should be registered with {@link AutoConfigurationPackages}.
* <p>
* Use {@link #basePackageClasses} for a type-safe alternative to String-based package
* names.
* @return the back package names
* @since 2.3.0
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages} for specifying the packages to be
* registered with {@link AutoConfigurationPackages}.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return the base package classes
* @since 2.3.0
*/
Class<?>[] basePackageClasses() default {};
}

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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,6 +34,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; @@ -34,6 +34,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.context.annotation.DeterminableImports;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
@ -120,12 +121,12 @@ public abstract class AutoConfigurationPackages { @@ -120,12 +121,12 @@ public abstract class AutoConfigurationPackages {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
return Collections.singleton(new PackageImports(metadata));
}
}
@ -133,16 +134,28 @@ public abstract class AutoConfigurationPackages { @@ -133,16 +134,28 @@ public abstract class AutoConfigurationPackages {
/**
* Wrapper for a package import.
*/
private static final class PackageImport {
private static final class PackageImports {
private final String packageName;
private final List<String> packageNames;
PackageImport(AnnotationMetadata metadata) {
this.packageName = ClassUtils.getPackageName(metadata.getClassName());
PackageImports(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(AutoConfigurationPackage.class.getName(), false));
List<String> packageNames = new ArrayList<>();
for (String basePackage : attributes.getStringArray("basePackages")) {
packageNames.add(basePackage);
}
for (Class<?> basePackageClass : attributes.getClassArray("basePackageClasses")) {
packageNames.add(basePackageClass.getPackage().getName());
}
if (packageNames.isEmpty()) {
packageNames.add(ClassUtils.getPackageName(metadata.getClassName()));
}
this.packageNames = Collections.unmodifiableList(packageNames);
}
String getPackageName() {
return this.packageName;
List<String> getPackageNames() {
return this.packageNames;
}
@Override
@ -150,17 +163,17 @@ public abstract class AutoConfigurationPackages { @@ -150,17 +163,17 @@ public abstract class AutoConfigurationPackages {
if (obj == null || getClass() != obj.getClass()) {
return false;
}
return this.packageName.equals(((PackageImport) obj).packageName);
return this.packageNames.equals(((PackageImports) obj).packageNames);
}
@Override
public int hashCode() {
return this.packageName.hashCode();
return this.packageNames.hashCode();
}
@Override
public String toString() {
return "Package Import " + this.packageName;
return "Package Imports " + this.packageNames;
}
}

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

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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.
@ -20,12 +20,10 @@ import java.util.List; @@ -20,12 +20,10 @@ import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages.Registrar;
import org.springframework.boot.autoconfigure.packagestest.one.FirstConfiguration;
import org.springframework.boot.autoconfigure.packagestest.two.SecondConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@ -41,7 +39,8 @@ public class AutoConfigurationPackagesTests { @@ -41,7 +39,8 @@ public class AutoConfigurationPackagesTests {
@Test
void setAndGet() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigWithRegistrar.class);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConfigWithAutoConfigurationPackage.class);
assertThat(AutoConfigurationPackages.get(context.getBeanFactory()))
.containsExactly(getClass().getPackage().getName());
}
@ -63,21 +62,43 @@ public class AutoConfigurationPackagesTests { @@ -63,21 +62,43 @@ public class AutoConfigurationPackagesTests {
assertThat(packages).containsOnly(package1.getName(), package2.getName());
}
@Test
void whenBasePackagesAreSpecifiedThenTheyAreRegistered() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConfigWithAutoConfigurationBasePackages.class);
List<String> packages = AutoConfigurationPackages.get(context.getBeanFactory());
assertThat(packages).containsExactly("com.example.alpha", "com.example.bravo");
}
@Test
void whenBasePackageClassesAreSpecifiedThenTheirPackagesAreRegistered() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConfigWithAutoConfigurationBasePackageClasses.class);
List<String> packages = AutoConfigurationPackages.get(context.getBeanFactory());
assertThat(packages).containsOnly(FirstConfiguration.class.getPackage().getName(),
SecondConfiguration.class.getPackage().getName());
}
@Configuration(proxyBeanMethods = false)
@Import(AutoConfigurationPackages.Registrar.class)
static class ConfigWithRegistrar {
@AutoConfigurationPackage
static class ConfigWithAutoConfigurationPackage {
}
@Configuration(proxyBeanMethods = false)
static class EmptyConfig {
@AutoConfigurationPackage(basePackages = { "com.example.alpha", "com.example.bravo" })
static class ConfigWithAutoConfigurationBasePackages {
}
/**
* Test helper to allow {@link Registrar} to be referenced from other packages.
*/
public static class TestRegistrar extends Registrar {
@Configuration(proxyBeanMethods = false)
@AutoConfigurationPackage(basePackageClasses = { FirstConfiguration.class, SecondConfiguration.class })
static class ConfigWithAutoConfigurationBasePackageClasses {
}
@Configuration(proxyBeanMethods = false)
static class EmptyConfig {
}

8
spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelectorTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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.
@ -171,12 +171,12 @@ class ImportAutoConfigurationImportSelectorTests { @@ -171,12 +171,12 @@ class ImportAutoConfigurationImportSelectorTests {
@Test
void determineImportsShouldNotSetPackageImport() throws Exception {
Class<?> packageImportClass = ClassUtils.resolveClassName(
"org.springframework.boot.autoconfigure.AutoConfigurationPackages.PackageImport", null);
Class<?> packageImportsClass = ClassUtils.resolveClassName(
"org.springframework.boot.autoconfigure.AutoConfigurationPackages.PackageImports", null);
Set<Object> selectedImports = this.importSelector
.determineImports(getAnnotationMetadata(ImportMetaAutoConfigurationExcludeWithUnrelatedOne.class));
for (Object selectedImport : selectedImports) {
assertThat(selectedImport).isNotInstanceOf(packageImportClass);
assertThat(selectedImport).isNotInstanceOf(packageImportsClass);
}
}

7
spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/one/FirstConfiguration.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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,9 +16,8 @@ @@ -16,9 +16,8 @@
package org.springframework.boot.autoconfigure.packagestest.one;
import org.springframework.boot.autoconfigure.AutoConfigurationPackagesTests.TestRegistrar;
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Sample configuration used in {@code AutoConfigurationPackagesTests}.
@ -26,7 +25,7 @@ import org.springframework.context.annotation.Import; @@ -26,7 +25,7 @@ import org.springframework.context.annotation.Import;
* @author Oliver Gierke
*/
@Configuration(proxyBeanMethods = false)
@Import(TestRegistrar.class)
@AutoConfigurationPackage
public class FirstConfiguration {
}

7
spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/packagestest/two/SecondConfiguration.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 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,10 +16,9 @@ @@ -16,10 +16,9 @@
package org.springframework.boot.autoconfigure.packagestest.two;
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
import org.springframework.boot.autoconfigure.AutoConfigurationPackagesTests;
import org.springframework.boot.autoconfigure.AutoConfigurationPackagesTests.TestRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Sample configuration used in {@link AutoConfigurationPackagesTests}.
@ -27,7 +26,7 @@ import org.springframework.context.annotation.Import; @@ -27,7 +26,7 @@ import org.springframework.context.annotation.Import;
* @author Oliver Gierke
*/
@Configuration(proxyBeanMethods = false)
@Import(TestRegistrar.class)
@AutoConfigurationPackage
public class SecondConfiguration {
}

Loading…
Cancel
Save