diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java index 6f757e316f0..9a9e85ce5ff 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScan.java @@ -23,6 +23,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.core.annotation.AliasFor; import org.springframework.core.type.filter.TypeFilter; /** @@ -46,6 +47,7 @@ import org.springframework.core.type.filter.TypeFilter; * * @author Chris Beams * @author Juergen Hoeller + * @author Sam Brannen * @since 3.1 * @see Configuration */ @@ -60,6 +62,7 @@ public @interface ComponentScan { * are needed — for example, {@code @ComponentScan("org.my.pkg")} * instead of {@code @ComponentScan(basePackages = "org.my.pkg")}. */ + @AliasFor(attribute = "basePackages") String[] value() default {}; /** @@ -69,6 +72,7 @@ public @interface ComponentScan { *

Use {@link #basePackageClasses} for a type-safe alternative to * String-based package names. */ + @AliasFor(attribute = "value") String[] basePackages() default {}; /** diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java index 7b0ef1c17ce..b07f67901bf 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ComponentScanAnnotationParser.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanNameGenerator; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.annotation.AnnotationConfigurationException; import org.springframework.core.env.Environment; import org.springframework.core.io.ResourceLoader; import org.springframework.core.type.filter.AbstractTypeHierarchyTraversingFilter; @@ -40,6 +41,7 @@ import org.springframework.core.type.filter.RegexPatternTypeFilter; import org.springframework.core.type.filter.TypeFilter; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** @@ -115,11 +117,7 @@ class ComponentScanAnnotationParser { } Set basePackages = new LinkedHashSet(); - Set specifiedPackages = new LinkedHashSet(); - specifiedPackages.addAll(Arrays.asList(componentScan.getStringArray("value"))); - specifiedPackages.addAll(Arrays.asList(componentScan.getStringArray("basePackages"))); - - for (String pkg : specifiedPackages) { + for (String pkg : getBasePackages(componentScan, declaringClass)) { String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg), ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); basePackages.addAll(Arrays.asList(tokenized)); @@ -140,6 +138,25 @@ class ComponentScanAnnotationParser { return scanner.doScan(StringUtils.toStringArray(basePackages)); } + private String[] getBasePackages(AnnotationAttributes componentScan, String declaringClass) { + String[] value = componentScan.getStringArray("value"); + String[] basePackages = componentScan.getStringArray("basePackages"); + boolean valueDeclared = !ObjectUtils.isEmpty(value); + boolean basePackagesDeclared = !ObjectUtils.isEmpty(basePackages); + + if (valueDeclared && basePackagesDeclared && !ObjectUtils.nullSafeEquals(value, basePackages)) { + String msg = String.format("In @ComponentScan declared on [%s], attribute [value] " + + "and its alias [basePackages] are present with values of [%s] and [%s], " + + "but only one is permitted.", declaringClass, ObjectUtils.nullSafeToString(value), + ObjectUtils.nullSafeToString(basePackages)); + throw new AnnotationConfigurationException(msg); + } + if (!basePackagesDeclared) { + basePackages = value; + } + return basePackages; + } + private List typeFiltersFor(AnnotationAttributes filterAttributes) { List typeFilters = new ArrayList(); FilterType filterType = filterAttributes.getEnum("type");