diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanPackages.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanPackages.java index 185a90fd57..e0c27c2cf1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanPackages.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanPackages.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.env.Environment; @@ -141,10 +142,13 @@ public class EntityScanPackages { .fromMap(metadata.getAnnotationAttributes(EntityScan.class.getName())); Set packagesToScan = new LinkedHashSet<>(); for (String basePackage : attributes.getStringArray("basePackages")) { - addResolvedPackage(basePackage, packagesToScan); + String[] tokenized = StringUtils.tokenizeToStringArray( + this.environment.resolvePlaceholders(basePackage), + ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); + Collections.addAll(packagesToScan, tokenized); } for (Class basePackageClass : attributes.getClassArray("basePackageClasses")) { - addResolvedPackage(ClassUtils.getPackageName(basePackageClass), packagesToScan); + packagesToScan.add(this.environment.resolvePlaceholders(ClassUtils.getPackageName(basePackageClass))); } if (packagesToScan.isEmpty()) { String packageName = ClassUtils.getPackageName(metadata.getClassName()); @@ -154,10 +158,6 @@ public class EntityScanPackages { return packagesToScan; } - private void addResolvedPackage(String packageName, Set packagesToScan) { - packagesToScan.add(this.environment.resolvePlaceholders(packageName)); - } - } static class EntityScanPackagesBeanDefinition extends GenericBeanDefinition { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScannerTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScannerTests.java index e78e03aec8..36c2cc3160 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScannerTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScannerTests.java @@ -119,6 +119,20 @@ class EntityScannerTests { assertThat(annotationTypeFilter.getValue().getAnnotationType()).isEqualTo(Entity.class); } + @Test + void scanShouldScanCommaSeparatedPackagesInPlaceholderPackage() throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + TestPropertyValues.of( + "com.example.entity-package=org.springframework.boot.autoconfigure.domain.scan.a,org.springframework.boot.autoconfigure.domain.scan.b") + .applyTo(context); + context.register(ScanPlaceholderConfig.class); + context.refresh(); + EntityScanner scanner = new EntityScanner(context); + Set> scanned = scanner.scan(Entity.class); + assertThat(scanned).containsOnly(EntityA.class, EntityB.class); + context.close(); + } + private static class TestEntityScanner extends EntityScanner { private final ClassPathScanningCandidateComponentProvider candidateComponentProvider;