/* * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.beans.factory.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.springframework.beans.SimpleTypeConverter; import org.springframework.beans.TypeConverter; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.DependencyDescriptor; import org.springframework.beans.factory.support.AutowireCandidateQualifier; import org.springframework.beans.factory.support.AutowireCandidateResolver; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; /** * {@link AutowireCandidateResolver} implementation that matches bean definition qualifiers * against {@link Qualifier qualifier annotations} on the field or parameter to be autowired. * Also supports suggested expression values through a {@link Value value} annotation. * *
Also supports JSR-330's {@link javax.inject.Qualifier} annotation, if available.
*
* @author Mark Fisher
* @author Juergen Hoeller
* @since 2.5
* @see AutowireCandidateQualifier
* @see Qualifier
* @see Value
*/
public class QualifierAnnotationAutowireCandidateResolver implements AutowireCandidateResolver, BeanFactoryAware {
private final Set Also supports JSR-330's {@link javax.inject.Qualifier} annotation, if available.
*/
@SuppressWarnings("unchecked")
public QualifierAnnotationAutowireCandidateResolver() {
this.qualifierTypes.add(Qualifier.class);
ClassLoader cl = QualifierAnnotationAutowireCandidateResolver.class.getClassLoader();
try {
this.qualifierTypes.add((Class extends Annotation>) cl.loadClass("javax.inject.Qualifier"));
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
/**
* Create a new QualifierAnnotationAutowireCandidateResolver
* for the given qualifier annotation type.
* @param qualifierType the qualifier annotation to look for
*/
public QualifierAnnotationAutowireCandidateResolver(Class extends Annotation> qualifierType) {
Assert.notNull(qualifierType, "'qualifierType' must not be null");
this.qualifierTypes.add(qualifierType);
}
/**
* Create a new QualifierAnnotationAutowireCandidateResolver
* for the given qualifier annotation types.
* @param qualifierTypes the qualifier annotations to look for
*/
public QualifierAnnotationAutowireCandidateResolver(Set This identifies qualifier annotations for direct use (on fields,
* method parameters and constructor parameters) as well as meta
* annotations that in turn identify actual qualifier annotations.
* This implementation only supports annotations as qualifier types.
* The default is Spring's {@link Qualifier} annotation which serves
* as a qualifier for direct use and also as a meta annotation.
* @param qualifierType the annotation type to register
*/
public void addQualifierType(Class extends Annotation> qualifierType) {
this.qualifierTypes.add(qualifierType);
}
/**
* Set the 'value' annotation type, to be used on fields, method parameters
* and constructor parameters.
* The default value annotation type is the Spring-provided
* {@link Value} annotation.
* This setter property exists so that developers can provide their own
* (non-Spring-specific) annotation type to indicate a default value
* expression for a specific argument.
*/
public void setValueAnnotationType(Class extends Annotation> valueAnnotationType) {
this.valueAnnotationType = valueAnnotationType;
}
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
/**
* Determine whether the provided bean definition is an autowire candidate.
* To be considered a candidate the bean's autowire-candidate
* attribute must not have been set to 'false'. Also, if an annotation on
* the field or parameter to be autowired is recognized by this bean factory
* as a qualifier, the bean must 'match' against the annotation as
* well as any attributes it may contain. The bean definition must contain
* the same qualifier or match by meta attributes. A "value" attribute will
* fallback to match against the bean name or an alias if a qualifier or
* attribute does not match.
* @see Qualifier
*/
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
if (!bdHolder.getBeanDefinition().isAutowireCandidate()) {
// if explicitly false, do not proceed with qualifier check
return false;
}
if (descriptor == null) {
// no qualification necessary
return true;
}
boolean match = checkQualifiers(bdHolder, descriptor.getAnnotations());
if (match) {
MethodParameter methodParam = descriptor.getMethodParameter();
if (methodParam != null) {
Method method = methodParam.getMethod();
if (method == null || void.class.equals(method.getReturnType())) {
match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
}
}
}
return match;
}
/**
* Match the given qualifier annotations against the candidate bean definition.
*/
protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
if (ObjectUtils.isEmpty(annotationsToSearch)) {
return true;
}
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
for (Annotation annotation : annotationsToSearch) {
Class extends Annotation> type = annotation.annotationType();
if (isQualifier(type)) {
if (!checkQualifier(bdHolder, annotation, typeConverter)) {
return false;
}
}
}
return true;
}
/**
* Checks whether the given annotation type is a recognized qualifier type.
*/
protected boolean isQualifier(Class extends Annotation> annotationType) {
for (Class extends Annotation> qualifierType : this.qualifierTypes) {
if (annotationType.equals(qualifierType) || annotationType.isAnnotationPresent(qualifierType)) {
return true;
}
}
return false;
}
/**
* Match the given qualifier annotation against the candidate bean definition.
*/
protected boolean checkQualifier(
BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) {
Class extends Annotation> type = annotation.annotationType();
RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
if (qualifier == null) {
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
}
if (qualifier == null) {
Annotation targetAnnotation = null;
if (bd.getResolvedFactoryMethod() != null) {
targetAnnotation = bd.getResolvedFactoryMethod().getAnnotation(type);
}
if (targetAnnotation == null) {
// look for matching annotation on the target class
if (this.beanFactory != null) {
Class> beanType = this.beanFactory.getType(bdHolder.getBeanName());
if (beanType != null) {
targetAnnotation = ClassUtils.getUserClass(beanType).getAnnotation(type);
}
}
if (targetAnnotation == null && bd.hasBeanClass()) {
targetAnnotation = ClassUtils.getUserClass(bd.getBeanClass()).getAnnotation(type);
}
}
if (targetAnnotation != null && targetAnnotation.equals(annotation)) {
return true;
}
}
Map