001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.beans.factory.annotation;
018:
019: import java.lang.annotation.Annotation;
020: import java.util.HashSet;
021: import java.util.Map;
022: import java.util.Set;
023:
024: import org.springframework.beans.SimpleTypeConverter;
025: import org.springframework.beans.factory.config.BeanDefinitionHolder;
026: import org.springframework.beans.factory.config.DependencyDescriptor;
027: import org.springframework.beans.factory.support.AbstractBeanDefinition;
028: import org.springframework.beans.factory.support.AutowireCandidateQualifier;
029: import org.springframework.beans.factory.support.AutowireCandidateResolver;
030: import org.springframework.core.annotation.AnnotationUtils;
031: import org.springframework.util.Assert;
032: import org.springframework.util.ClassUtils;
033: import org.springframework.util.ObjectUtils;
034:
035: /**
036: * {@link AutowireCandidateResolver} implementation that matches bean definition
037: * qualifiers against qualifier annotations on the field or parameter to be autowired.
038: *
039: * @author Mark Fisher
040: * @author Juergen Hoeller
041: * @since 2.5
042: * @see AutowireCandidateQualifier
043: * @see Qualifier
044: */
045: public class QualifierAnnotationAutowireCandidateResolver implements
046: AutowireCandidateResolver {
047:
048: private final Set<Class<? extends Annotation>> qualifierTypes;
049:
050: /**
051: * Create a new QualifierAnnotationAutowireCandidateResolver
052: * for Spring's standard {@link Qualifier} annotation.
053: */
054: public QualifierAnnotationAutowireCandidateResolver() {
055: this .qualifierTypes = new HashSet<Class<? extends Annotation>>(
056: 1);
057: this .qualifierTypes.add(Qualifier.class);
058: }
059:
060: /**
061: * Create a new QualifierAnnotationAutowireCandidateResolver
062: * for the given qualifier annotation type.
063: * @param qualifierType the qualifier annotation to look for
064: */
065: public QualifierAnnotationAutowireCandidateResolver(
066: Class<? extends Annotation> qualifierType) {
067: Assert.notNull(qualifierType,
068: "'qualifierType' must not be null");
069: this .qualifierTypes = new HashSet<Class<? extends Annotation>>(
070: 1);
071: this .qualifierTypes.add(qualifierType);
072: }
073:
074: /**
075: * Create a new QualifierAnnotationAutowireCandidateResolver
076: * for the given qualifier annotation types.
077: * @param qualifierTypes the qualifier annotations to look for
078: */
079: public QualifierAnnotationAutowireCandidateResolver(
080: Set<Class<? extends Annotation>> qualifierTypes) {
081: Assert.notNull(qualifierTypes,
082: "'qualifierTypes' must not be null");
083: this .qualifierTypes = new HashSet<Class<? extends Annotation>>(
084: qualifierTypes);
085: }
086:
087: /**
088: * Register the given type to be used as a qualifier when autowiring.
089: * <p>This implementation only supports annotations as qualifier types.
090: * @param qualifierType the annotation type to register
091: */
092: public void addQualifierType(
093: Class<? extends Annotation> qualifierType) {
094: this .qualifierTypes.add(qualifierType);
095: }
096:
097: /**
098: * Determine if the provided bean definition is an autowire candidate.
099: * <p>To be considered a candidate the bean's <em>autowire-candidate</em>
100: * attribute must not have been set to 'false'. Also if an annotation on
101: * the field or parameter to be autowired is recognized by this bean factory
102: * as a <em>qualifier</em>, the bean must 'match' against the annotation as
103: * well as any attributes it may contain. The bean definition must contain
104: * the same qualifier or match by meta attributes. A "value" attribute will
105: * fallback to match against the bean name or an alias if a qualifier or
106: * attribute does not match.
107: */
108: public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder,
109: DependencyDescriptor descriptor) {
110: if (!bdHolder.getBeanDefinition().isAutowireCandidate()) {
111: // if explicitly false, do not proceed with qualifier check
112: return false;
113: }
114: if (descriptor == null
115: || ObjectUtils.isEmpty(descriptor.getAnnotations())) {
116: // no qualification necessary
117: return true;
118: }
119: AbstractBeanDefinition bd = (AbstractBeanDefinition) bdHolder
120: .getBeanDefinition();
121: SimpleTypeConverter typeConverter = new SimpleTypeConverter();
122: Annotation[] annotations = (Annotation[]) descriptor
123: .getAnnotations();
124: for (Annotation annotation : annotations) {
125: Class<? extends Annotation> type = annotation
126: .annotationType();
127: if (isQualifier(type)) {
128: AutowireCandidateQualifier qualifier = bd
129: .getQualifier(type.getName());
130: if (qualifier == null) {
131: qualifier = bd.getQualifier(ClassUtils
132: .getShortName(type));
133: }
134: if (qualifier == null && bd.hasBeanClass()) {
135: // look for matching annotation on the target class
136: Class<?> beanClass = bd.getBeanClass();
137: Annotation targetAnnotation = beanClass
138: .getAnnotation(type);
139: if (targetAnnotation != null
140: && targetAnnotation.equals(annotation)) {
141: return true;
142: }
143: }
144: Map<String, Object> attributes = AnnotationUtils
145: .getAnnotationAttributes(annotation);
146: if (attributes.isEmpty() && qualifier == null) {
147: // if no attributes, the qualifier must be present
148: return false;
149: }
150: for (Map.Entry<String, Object> entry : attributes
151: .entrySet()) {
152: String attributeName = entry.getKey();
153: Object expectedValue = entry.getValue();
154: Object actualValue = null;
155: // check qualifier first
156: if (qualifier != null) {
157: actualValue = qualifier
158: .getAttribute(attributeName);
159: }
160: if (actualValue == null) {
161: // fall back on bean definition attribute
162: actualValue = bd.getAttribute(attributeName);
163: }
164: if (actualValue == null
165: && attributeName
166: .equals(AutowireCandidateQualifier.VALUE_KEY)
167: && (expectedValue.equals(bdHolder
168: .getBeanName()) || ObjectUtils
169: .containsElement(bdHolder
170: .getAliases(),
171: expectedValue))) {
172: // fall back on bean name (or alias) match
173: continue;
174: }
175: if (actualValue == null && qualifier != null) {
176: // fall back on default, but only if the qualifier is present
177: actualValue = AnnotationUtils.getDefaultValue(
178: annotation, attributeName);
179: }
180: if (actualValue != null) {
181: actualValue = typeConverter.convertIfNecessary(
182: actualValue, expectedValue.getClass());
183: }
184: if (!expectedValue.equals(actualValue)) {
185: return false;
186: }
187: }
188: }
189: }
190: return true;
191: }
192:
193: /**
194: * Checks whether the given annotation type is a recognized qualifier type.
195: */
196: private boolean isQualifier(
197: Class<? extends Annotation> annotationType) {
198: for (Class<? extends Annotation> qualifierType : this .qualifierTypes) {
199: if (annotationType.equals(qualifierType)
200: || annotationType
201: .isAnnotationPresent(qualifierType)) {
202: return true;
203: }
204: }
205: return false;
206: }
207:
208: }
|