diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java index 5bbed07d91..657ee22666 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/QualifierAnnotationAutowireCandidateResolver.java @@ -36,6 +36,7 @@ import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; /** * {@link AutowireCandidateResolver} implementation that matches bean definition qualifiers @@ -192,7 +193,7 @@ public class QualifierAnnotationAutowireCandidateResolver implements AutowireCan foundMeta = true; // Only accept fallback match if @Qualifier annotation has a value... // Otherwise it is just a marker for a custom qualifier annotation. - if ((fallbackToMeta && AnnotationUtils.getValue(metaAnn) == null) || + if ((fallbackToMeta && StringUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) || !checkQualifier(bdHolder, metaAnn, typeConverter)) { return false; } diff --git a/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java b/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java index b3fc360aa3..e5c14903e2 100644 --- a/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java +++ b/spring-context/src/test/java/org/springframework/beans/factory/support/QualifierAnnotationAutowireContextTests.java @@ -167,7 +167,7 @@ public class QualifierAnnotationAutowireContextTests { RootBeanDefinition person = new RootBeanDefinition(QualifiedPerson.class, cavs, null); ConstructorArgumentValues cavs2 = new ConstructorArgumentValues(); cavs2.addGenericArgumentValue(MARK); - RootBeanDefinition person2 = new RootBeanDefinition(Person.class, cavs2, null); + RootBeanDefinition person2 = new RootBeanDefinition(DefaultValueQualifiedPerson.class, cavs2, null); context.registerBeanDefinition(JUERGEN, person); context.registerBeanDefinition(MARK, person2); context.registerBeanDefinition("autowired", @@ -745,13 +745,25 @@ public class QualifierAnnotationAutowireContextTests { } + @TestQualifierWithDefaultValue + private static class DefaultValueQualifiedPerson extends Person { + + public DefaultValueQualifiedPerson() { + super(null); + } + + public DefaultValueQualifiedPerson(String name) { + super(name); + } + } + + @Retention(RetentionPolicy.RUNTIME) @Qualifier public static @interface TestQualifier { } - @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Qualifier public static @interface TestQualifierWithDefaultValue { diff --git a/spring-core/src/main/java/org/springframework/util/StringUtils.java b/spring-core/src/main/java/org/springframework/util/StringUtils.java index c44c0c4ca7..52874fb729 100644 --- a/spring-core/src/main/java/org/springframework/util/StringUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StringUtils.java @@ -69,6 +69,21 @@ public abstract class StringUtils { // General convenience methods for working with Strings //--------------------------------------------------------------------- + /** + * Check whether the given String is empty. + *

This method accepts any Object as an argument, comparing it to + * null and the empty String. As a consequence, this method + * will never return true for a non-null non-String object. + *

The Object signature is useful for general attribute handling code + * that commonly deals with Strings but generally has to iterate over + * Objects since attributes may e.g. be primitive value objects as well. + * @param str the candidate String + * @since 3.2.1 + */ + public static boolean isEmpty(Object str) { + return (str == null || "".equals(str)); + } + /** * Check that the given CharSequence is neither null nor of length 0. * Note: Will return true for a CharSequence that purely consists of whitespace.