11/*
2- * Copyright 2002-2015 the original author or authors.
2+ * Copyright 2002-2016 the original author or authors.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1717package org .springframework .beans .factory .annotation ;
1818
1919import java .lang .reflect .Method ;
20+ import java .util .function .Predicate ;
2021
22+ import org .springframework .beans .BeansException ;
2123import org .springframework .beans .factory .BeanFactory ;
2224import org .springframework .beans .factory .BeanFactoryUtils ;
2325import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
26+ import org .springframework .beans .factory .NoUniqueBeanDefinitionException ;
2427import org .springframework .beans .factory .config .BeanDefinition ;
28+ import org .springframework .beans .factory .config .ConfigurableBeanFactory ;
2529import org .springframework .beans .factory .config .ConfigurableListableBeanFactory ;
2630import org .springframework .beans .factory .support .AbstractBeanDefinition ;
2731import org .springframework .beans .factory .support .AutowireCandidateQualifier ;
2832import org .springframework .beans .factory .support .RootBeanDefinition ;
2933import org .springframework .core .annotation .AnnotationUtils ;
30- import org .springframework .util .ObjectUtils ;
34+ import org .springframework .util .Assert ;
3135
3236/**
3337 * Convenience methods performing bean lookups related to annotations, for example
3438 * Spring's {@link Qualifier @Qualifier} annotation.
3539 *
36- * @author Chris Beams
3740 * @author Juergen Hoeller
41+ * @author Chris Beams
3842 * @since 3.1.2
3943 * @see BeanFactoryUtils
4044 */
41- public class BeanFactoryAnnotationUtils {
45+ public abstract class BeanFactoryAnnotationUtils {
4246
4347 /**
4448 * Obtain a bean of type {@code T} from the given {@code BeanFactory} declaring a
@@ -48,9 +52,16 @@ public class BeanFactoryAnnotationUtils {
4852 * @param beanType the type of bean to retrieve
4953 * @param qualifier the qualifier for selecting between multiple bean matches
5054 * @return the matching bean of type {@code T} (never {@code null})
55+ * @throws NoUniqueBeanDefinitionException if multiple matching beans of type {@code T} found
5156 * @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
57+ * @throws BeansException if the bean could not be created
58+ * @see BeanFactory#getBean(Class)
5259 */
53- public static <T > T qualifiedBeanOfType (BeanFactory beanFactory , Class <T > beanType , String qualifier ) {
60+ public static <T > T qualifiedBeanOfType (BeanFactory beanFactory , Class <T > beanType , String qualifier )
61+ throws BeansException {
62+
63+ Assert .notNull (beanFactory , "BeanFactory must not be null" );
64+
5465 if (beanFactory instanceof ConfigurableListableBeanFactory ) {
5566 // Full qualifier matching supported.
5667 return qualifiedBeanOfType ((ConfigurableListableBeanFactory ) beanFactory , beanType , qualifier );
@@ -74,16 +85,14 @@ else if (beanFactory.containsBean(qualifier)) {
7485 * @param beanType the type of bean to retrieve
7586 * @param qualifier the qualifier for selecting between multiple bean matches
7687 * @return the matching bean of type {@code T} (never {@code null})
77- * @throws NoSuchBeanDefinitionException if no matching bean of type {@code T} found
7888 */
7989 private static <T > T qualifiedBeanOfType (ConfigurableListableBeanFactory bf , Class <T > beanType , String qualifier ) {
8090 String [] candidateBeans = BeanFactoryUtils .beanNamesForTypeIncludingAncestors (bf , beanType );
8191 String matchingBean = null ;
8292 for (String beanName : candidateBeans ) {
83- if (isQualifierMatch (qualifier , beanName , bf )) {
93+ if (isQualifierMatch (qualifier :: equals , beanName , bf )) {
8494 if (matchingBean != null ) {
85- throw new NoSuchBeanDefinitionException (qualifier , "No unique " + beanType .getSimpleName () +
86- " bean found for qualifier '" + qualifier + "'" );
95+ throw new NoUniqueBeanDefinitionException (beanType , matchingBean , beanName );
8796 }
8897 matchingBean = beanName ;
8998 }
@@ -105,40 +114,54 @@ else if (bf.containsBean(qualifier)) {
105114 * Check whether the named bean declares a qualifier of the given name.
106115 * @param qualifier the qualifier to match
107116 * @param beanName the name of the candidate bean
108- * @param bf the {@code BeanFactory} from which to retrieve the named bean
117+ * @param beanFactory the {@code BeanFactory} from which to retrieve the named bean
109118 * @return {@code true} if either the bean definition (in the XML case)
110119 * or the bean's factory method (in the {@code @Bean} case) defines a matching
111120 * qualifier value (through {@code <qualifier>} or {@code @Qualifier})
121+ * @since 5.0
112122 */
113- private static boolean isQualifierMatch (String qualifier , String beanName , ConfigurableListableBeanFactory bf ) {
114- if (bf .containsBean (beanName )) {
123+ public static boolean isQualifierMatch (Predicate <String > qualifier , String beanName , BeanFactory beanFactory ) {
124+ // Try quick bean name or alias match first...
125+ if (qualifier .test (beanName )) {
126+ return true ;
127+ }
128+ if (beanFactory != null ) {
129+ for (String alias : beanFactory .getAliases (beanName )) {
130+ if (qualifier .test (alias )) {
131+ return true ;
132+ }
133+ }
115134 try {
116- BeanDefinition bd = bf .getMergedBeanDefinition (beanName );
117- // Explicit qualifier metadata on bean definition? (typically in XML definition)
118- if (bd instanceof AbstractBeanDefinition ) {
119- AbstractBeanDefinition abd = (AbstractBeanDefinition ) bd ;
120- AutowireCandidateQualifier candidate = abd .getQualifier (Qualifier .class .getName ());
121- if ((candidate != null && qualifier .equals (candidate .getAttribute (AutowireCandidateQualifier .VALUE_KEY ))) ||
122- qualifier .equals (beanName ) || ObjectUtils .containsElement (bf .getAliases (beanName ), qualifier )) {
123- return true ;
135+ if (beanFactory instanceof ConfigurableBeanFactory ) {
136+ BeanDefinition bd = ((ConfigurableBeanFactory ) beanFactory ).getMergedBeanDefinition (beanName );
137+ // Explicit qualifier metadata on bean definition? (typically in XML definition)
138+ if (bd instanceof AbstractBeanDefinition ) {
139+ AbstractBeanDefinition abd = (AbstractBeanDefinition ) bd ;
140+ AutowireCandidateQualifier candidate = abd .getQualifier (Qualifier .class .getName ());
141+ if (candidate != null ) {
142+ Object value = candidate .getAttribute (AutowireCandidateQualifier .VALUE_KEY );
143+ if (value != null && qualifier .test (value .toString ())) {
144+ return true ;
145+ }
146+ }
124147 }
125- }
126- // Corresponding qualifier on factory method? (typically in configuration class)
127- if ( bd instanceof RootBeanDefinition ) {
128- Method factoryMethod = (( RootBeanDefinition ) bd ). getResolvedFactoryMethod ();
129- if ( factoryMethod != null ) {
130- Qualifier targetAnnotation = AnnotationUtils . getAnnotation ( factoryMethod , Qualifier . class );
131- if (targetAnnotation != null ) {
132- return qualifier . equals ( targetAnnotation . value ());
148+ // Corresponding qualifier on factory method? (typically in configuration class)
149+ if ( bd instanceof RootBeanDefinition ) {
150+ Method factoryMethod = (( RootBeanDefinition ) bd ). getResolvedFactoryMethod ();
151+ if ( factoryMethod != null ) {
152+ Qualifier targetAnnotation = AnnotationUtils . getAnnotation ( factoryMethod , Qualifier . class );
153+ if ( targetAnnotation != null ) {
154+ return qualifier . test (targetAnnotation . value ());
155+ }
133156 }
134157 }
135158 }
136159 // Corresponding qualifier on bean implementation class? (for custom user types)
137- Class <?> beanType = bf .getType (beanName );
160+ Class <?> beanType = beanFactory .getType (beanName );
138161 if (beanType != null ) {
139162 Qualifier targetAnnotation = AnnotationUtils .getAnnotation (beanType , Qualifier .class );
140163 if (targetAnnotation != null ) {
141- return qualifier .equals (targetAnnotation .value ());
164+ return qualifier .test (targetAnnotation .value ());
142165 }
143166 }
144167 }
0 commit comments