001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.beans.factory.annotation; 018 019import java.lang.annotation.Annotation; 020import java.lang.reflect.AnnotatedElement; 021import java.lang.reflect.Method; 022import java.util.LinkedHashSet; 023import java.util.Map; 024import java.util.Set; 025 026import org.springframework.beans.SimpleTypeConverter; 027import org.springframework.beans.TypeConverter; 028import org.springframework.beans.factory.NoSuchBeanDefinitionException; 029import org.springframework.beans.factory.config.BeanDefinitionHolder; 030import org.springframework.beans.factory.config.DependencyDescriptor; 031import org.springframework.beans.factory.support.AutowireCandidateQualifier; 032import org.springframework.beans.factory.support.AutowireCandidateResolver; 033import org.springframework.beans.factory.support.GenericTypeAwareAutowireCandidateResolver; 034import org.springframework.beans.factory.support.RootBeanDefinition; 035import org.springframework.core.MethodParameter; 036import org.springframework.core.annotation.AnnotatedElementUtils; 037import org.springframework.core.annotation.AnnotationAttributes; 038import org.springframework.core.annotation.AnnotationUtils; 039import org.springframework.util.Assert; 040import org.springframework.util.ClassUtils; 041import org.springframework.util.ObjectUtils; 042import org.springframework.util.StringUtils; 043 044/** 045 * {@link AutowireCandidateResolver} implementation that matches bean definition qualifiers 046 * against {@link Qualifier qualifier annotations} on the field or parameter to be autowired. 047 * Also supports suggested expression values through a {@link Value value} annotation. 048 * 049 * <p>Also supports JSR-330's {@link javax.inject.Qualifier} annotation, if available. 050 * 051 * @author Mark Fisher 052 * @author Juergen Hoeller 053 * @author Stephane Nicoll 054 * @since 2.5 055 * @see AutowireCandidateQualifier 056 * @see Qualifier 057 * @see Value 058 */ 059public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwareAutowireCandidateResolver { 060 061 private final Set<Class<? extends Annotation>> qualifierTypes = new LinkedHashSet<Class<? extends Annotation>>(2); 062 063 private Class<? extends Annotation> valueAnnotationType = Value.class; 064 065 066 /** 067 * Create a new QualifierAnnotationAutowireCandidateResolver 068 * for Spring's standard {@link Qualifier} annotation. 069 * <p>Also supports JSR-330's {@link javax.inject.Qualifier} annotation, if available. 070 */ 071 @SuppressWarnings("unchecked") 072 public QualifierAnnotationAutowireCandidateResolver() { 073 this.qualifierTypes.add(Qualifier.class); 074 try { 075 this.qualifierTypes.add((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Qualifier", 076 QualifierAnnotationAutowireCandidateResolver.class.getClassLoader())); 077 } 078 catch (ClassNotFoundException ex) { 079 // JSR-330 API not available - simply skip. 080 } 081 } 082 083 /** 084 * Create a new QualifierAnnotationAutowireCandidateResolver 085 * for the given qualifier annotation type. 086 * @param qualifierType the qualifier annotation to look for 087 */ 088 public QualifierAnnotationAutowireCandidateResolver(Class<? extends Annotation> qualifierType) { 089 Assert.notNull(qualifierType, "'qualifierType' must not be null"); 090 this.qualifierTypes.add(qualifierType); 091 } 092 093 /** 094 * Create a new QualifierAnnotationAutowireCandidateResolver 095 * for the given qualifier annotation types. 096 * @param qualifierTypes the qualifier annotations to look for 097 */ 098 public QualifierAnnotationAutowireCandidateResolver(Set<Class<? extends Annotation>> qualifierTypes) { 099 Assert.notNull(qualifierTypes, "'qualifierTypes' must not be null"); 100 this.qualifierTypes.addAll(qualifierTypes); 101 } 102 103 104 /** 105 * Register the given type to be used as a qualifier when autowiring. 106 * <p>This identifies qualifier annotations for direct use (on fields, 107 * method parameters and constructor parameters) as well as meta 108 * annotations that in turn identify actual qualifier annotations. 109 * <p>This implementation only supports annotations as qualifier types. 110 * The default is Spring's {@link Qualifier} annotation which serves 111 * as a qualifier for direct use and also as a meta annotation. 112 * @param qualifierType the annotation type to register 113 */ 114 public void addQualifierType(Class<? extends Annotation> qualifierType) { 115 this.qualifierTypes.add(qualifierType); 116 } 117 118 /** 119 * Set the 'value' annotation type, to be used on fields, method parameters 120 * and constructor parameters. 121 * <p>The default value annotation type is the Spring-provided 122 * {@link Value} annotation. 123 * <p>This setter property exists so that developers can provide their own 124 * (non-Spring-specific) annotation type to indicate a default value 125 * expression for a specific argument. 126 */ 127 public void setValueAnnotationType(Class<? extends Annotation> valueAnnotationType) { 128 this.valueAnnotationType = valueAnnotationType; 129 } 130 131 132 /** 133 * Determine whether the provided bean definition is an autowire candidate. 134 * <p>To be considered a candidate the bean's <em>autowire-candidate</em> 135 * attribute must not have been set to 'false'. Also, if an annotation on 136 * the field or parameter to be autowired is recognized by this bean factory 137 * as a <em>qualifier</em>, the bean must 'match' against the annotation as 138 * well as any attributes it may contain. The bean definition must contain 139 * the same qualifier or match by meta attributes. A "value" attribute will 140 * fallback to match against the bean name or an alias if a qualifier or 141 * attribute does not match. 142 * @see Qualifier 143 */ 144 @Override 145 public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) { 146 boolean match = super.isAutowireCandidate(bdHolder, descriptor); 147 if (match && descriptor != null) { 148 match = checkQualifiers(bdHolder, descriptor.getAnnotations()); 149 if (match) { 150 MethodParameter methodParam = descriptor.getMethodParameter(); 151 if (methodParam != null) { 152 Method method = methodParam.getMethod(); 153 if (method == null || void.class == method.getReturnType()) { 154 match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations()); 155 } 156 } 157 } 158 } 159 return match; 160 } 161 162 /** 163 * Match the given qualifier annotations against the candidate bean definition. 164 */ 165 protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) { 166 if (ObjectUtils.isEmpty(annotationsToSearch)) { 167 return true; 168 } 169 SimpleTypeConverter typeConverter = new SimpleTypeConverter(); 170 for (Annotation annotation : annotationsToSearch) { 171 Class<? extends Annotation> type = annotation.annotationType(); 172 boolean checkMeta = true; 173 boolean fallbackToMeta = false; 174 if (isQualifier(type)) { 175 if (!checkQualifier(bdHolder, annotation, typeConverter)) { 176 fallbackToMeta = true; 177 } 178 else { 179 checkMeta = false; 180 } 181 } 182 if (checkMeta) { 183 boolean foundMeta = false; 184 for (Annotation metaAnn : type.getAnnotations()) { 185 Class<? extends Annotation> metaType = metaAnn.annotationType(); 186 if (isQualifier(metaType)) { 187 foundMeta = true; 188 // Only accept fallback match if @Qualifier annotation has a value... 189 // Otherwise it is just a marker for a custom qualifier annotation. 190 if ((fallbackToMeta && StringUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) || 191 !checkQualifier(bdHolder, metaAnn, typeConverter)) { 192 return false; 193 } 194 } 195 } 196 if (fallbackToMeta && !foundMeta) { 197 return false; 198 } 199 } 200 } 201 return true; 202 } 203 204 /** 205 * Checks whether the given annotation type is a recognized qualifier type. 206 */ 207 protected boolean isQualifier(Class<? extends Annotation> annotationType) { 208 for (Class<? extends Annotation> qualifierType : this.qualifierTypes) { 209 if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) { 210 return true; 211 } 212 } 213 return false; 214 } 215 216 /** 217 * Match the given qualifier annotation against the candidate bean definition. 218 */ 219 protected boolean checkQualifier( 220 BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) { 221 222 Class<? extends Annotation> type = annotation.annotationType(); 223 RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition(); 224 225 AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName()); 226 if (qualifier == null) { 227 qualifier = bd.getQualifier(ClassUtils.getShortName(type)); 228 } 229 if (qualifier == null) { 230 // First, check annotation on qualified element, if any 231 Annotation targetAnnotation = getQualifiedElementAnnotation(bd, type); 232 // Then, check annotation on factory method, if applicable 233 if (targetAnnotation == null) { 234 targetAnnotation = getFactoryMethodAnnotation(bd, type); 235 } 236 if (targetAnnotation == null) { 237 RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd); 238 if (dbd != null) { 239 targetAnnotation = getFactoryMethodAnnotation(dbd, type); 240 } 241 } 242 if (targetAnnotation == null) { 243 // Look for matching annotation on the target class 244 if (getBeanFactory() != null) { 245 try { 246 Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName()); 247 if (beanType != null) { 248 targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(beanType), type); 249 } 250 } 251 catch (NoSuchBeanDefinitionException ex) { 252 // Not the usual case - simply forget about the type check... 253 } 254 } 255 if (targetAnnotation == null && bd.hasBeanClass()) { 256 targetAnnotation = AnnotationUtils.getAnnotation(ClassUtils.getUserClass(bd.getBeanClass()), type); 257 } 258 } 259 if (targetAnnotation != null && targetAnnotation.equals(annotation)) { 260 return true; 261 } 262 } 263 264 Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation); 265 if (attributes.isEmpty() && qualifier == null) { 266 // If no attributes, the qualifier must be present 267 return false; 268 } 269 for (Map.Entry<String, Object> entry : attributes.entrySet()) { 270 String attributeName = entry.getKey(); 271 Object expectedValue = entry.getValue(); 272 Object actualValue = null; 273 // Check qualifier first 274 if (qualifier != null) { 275 actualValue = qualifier.getAttribute(attributeName); 276 } 277 if (actualValue == null) { 278 // Fall back on bean definition attribute 279 actualValue = bd.getAttribute(attributeName); 280 } 281 if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) && 282 expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)) { 283 // Fall back on bean name (or alias) match 284 continue; 285 } 286 if (actualValue == null && qualifier != null) { 287 // Fall back on default, but only if the qualifier is present 288 actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName); 289 } 290 if (actualValue != null) { 291 actualValue = typeConverter.convertIfNecessary(actualValue, expectedValue.getClass()); 292 } 293 if (!expectedValue.equals(actualValue)) { 294 return false; 295 } 296 } 297 return true; 298 } 299 300 protected Annotation getQualifiedElementAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) { 301 AnnotatedElement qualifiedElement = bd.getQualifiedElement(); 302 return (qualifiedElement != null ? AnnotationUtils.getAnnotation(qualifiedElement, type) : null); 303 } 304 305 protected Annotation getFactoryMethodAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) { 306 Method resolvedFactoryMethod = bd.getResolvedFactoryMethod(); 307 return (resolvedFactoryMethod != null ? AnnotationUtils.getAnnotation(resolvedFactoryMethod, type) : null); 308 } 309 310 311 /** 312 * Determine whether the given dependency declares an autowired annotation, 313 * checking its required flag. 314 * @see Autowired#required() 315 */ 316 @Override 317 public boolean isRequired(DependencyDescriptor descriptor) { 318 if (!super.isRequired(descriptor)) { 319 return false; 320 } 321 Autowired autowired = descriptor.getAnnotation(Autowired.class); 322 return (autowired == null || autowired.required()); 323 } 324 325 /** 326 * Determine whether the given dependency declares a value annotation. 327 * @see Value 328 */ 329 @Override 330 public Object getSuggestedValue(DependencyDescriptor descriptor) { 331 Object value = findValue(descriptor.getAnnotations()); 332 if (value == null) { 333 MethodParameter methodParam = descriptor.getMethodParameter(); 334 if (methodParam != null) { 335 value = findValue(methodParam.getMethodAnnotations()); 336 } 337 } 338 return value; 339 } 340 341 /** 342 * Determine a suggested value from any of the given candidate annotations. 343 */ 344 protected Object findValue(Annotation[] annotationsToSearch) { 345 if (annotationsToSearch.length > 0) { // qualifier annotations have to be local 346 AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes( 347 AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType); 348 if (attr != null) { 349 return extractValue(attr); 350 } 351 } 352 return null; 353 } 354 355 /** 356 * Extract the value attribute from the given annotation. 357 * @since 4.3 358 */ 359 protected Object extractValue(AnnotationAttributes attr) { 360 Object value = attr.get(AnnotationUtils.VALUE); 361 if (value == null) { 362 throw new IllegalStateException("Value annotation must have a value attribute"); 363 } 364 return value; 365 } 366 367}