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.beans.PropertyDescriptor;
020: import java.lang.annotation.Annotation;
021: import java.lang.reflect.Constructor;
022: import java.lang.reflect.Field;
023: import java.lang.reflect.InvocationTargetException;
024: import java.lang.reflect.Member;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import java.util.LinkedHashSet;
030: import java.util.List;
031: import java.util.Map;
032: import java.util.Set;
033: import java.util.concurrent.ConcurrentHashMap;
034:
035: import org.apache.commons.logging.Log;
036: import org.apache.commons.logging.LogFactory;
037:
038: import org.springframework.beans.BeanUtils;
039: import org.springframework.beans.BeansException;
040: import org.springframework.beans.PropertyValues;
041: import org.springframework.beans.TypeConverter;
042: import org.springframework.beans.factory.BeanCreationException;
043: import org.springframework.beans.factory.BeanFactory;
044: import org.springframework.beans.factory.BeanFactoryAware;
045: import org.springframework.beans.factory.BeanFactoryUtils;
046: import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
047: import org.springframework.beans.factory.config.DependencyDescriptor;
048: import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
049: import org.springframework.core.MethodParameter;
050: import org.springframework.core.Ordered;
051: import org.springframework.core.PriorityOrdered;
052: import org.springframework.util.Assert;
053: import org.springframework.util.ReflectionUtils;
054:
055: /**
056: * {@link org.springframework.beans.factory.config.BeanPostProcessor} implementation
057: * that autowires annotated fields, setter methods and arbitrary config methods.
058: * Such members to be injected are detected through a Java 5 annotation:
059: * by default, Spring's {@link Autowired} annotation.
060: *
061: * <p>Only one constructor (at max) of any given bean class may carry this
062: * annotation with the 'required' parameter set to <code>true</code>,
063: * indicating <i>the</i> constructor to autowire when used as a Spring bean.
064: * If multiple <i>non-required</i> constructors carry the annotation, they
065: * will be considered as candidates for autowiring. The constructor with
066: * the greatest number of dependencies that can be satisfied by matching
067: * beans in the Spring container will be chosen. If none of the candidates
068: * can be satisfied, then a default constructor (if present) will be used.
069: * An annotated constructor does not have to be public.
070: *
071: * <p>Fields are injected right after construction of a bean, before any
072: * config methods are invoked. Such a config field does not have to be public.
073: *
074: * <p>Config methods may have an arbitrary name and any number of arguments;
075: * each of those arguments will be autowired with a matching bean in the
076: * Spring container. Bean property setter methods are effectively just
077: * a special case of such a general config method. Such config methods
078: * do not have to be public.
079: *
080: * <p>Note: A default AutowiredAnnotationBeanPostProcessor will be registered
081: * by the "context:annotation-config" and "context:component-scan" XML tags.
082: * Remove or turn off the default annotation configuration there if you intend
083: * to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.
084: *
085: * @author Juergen Hoeller
086: * @author Mark Fisher
087: * @since 2.5
088: * @see #setAutowiredAnnotationType
089: * @see Autowired
090: * @see org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
091: */
092: public class AutowiredAnnotationBeanPostProcessor extends
093: InstantiationAwareBeanPostProcessorAdapter implements
094: PriorityOrdered, BeanFactoryAware {
095:
096: protected final Log logger = LogFactory
097: .getLog(AutowiredAnnotationBeanPostProcessor.class);
098:
099: private Class<? extends Annotation> autowiredAnnotationType = Autowired.class;
100:
101: private String requiredParameterName = "required";
102:
103: private boolean requiredParameterValue = true;
104:
105: private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered
106:
107: private ConfigurableListableBeanFactory beanFactory;
108:
109: private final Map<Class<?>, Constructor[]> candidateConstructorsCache = new ConcurrentHashMap<Class<?>, Constructor[]>();
110:
111: private final Map<Class<?>, InjectionMetadata> injectionMetadataCache = new ConcurrentHashMap<Class<?>, InjectionMetadata>();
112:
113: /**
114: * Set the 'autowired' annotation type, to be used on constructors, fields,
115: * setter methods and arbitrary config methods.
116: * <p>The default autowired annotation type is the Spring-provided
117: * {@link Autowired} annotation.
118: * <p>This setter property exists so that developers can provide their own
119: * (non-Spring-specific) annotation type to indicate that a member is
120: * supposed to be autowired.
121: */
122: public void setAutowiredAnnotationType(
123: Class<? extends Annotation> autowiredAnnotationType) {
124: Assert.notNull(autowiredAnnotationType,
125: "'autowiredAnnotationType' must not be null");
126: this .autowiredAnnotationType = autowiredAnnotationType;
127: }
128:
129: /**
130: * Return the 'autowired' annotation type.
131: */
132: protected Class<? extends Annotation> getAutowiredAnnotationType() {
133: return this .autowiredAnnotationType;
134: }
135:
136: /**
137: * Set the name of a parameter of the annotation that specifies
138: * whether it is required.
139: * @see #setRequiredParameterValue(boolean)
140: */
141: public void setRequiredParameterName(String requiredParameterName) {
142: this .requiredParameterName = requiredParameterName;
143: }
144:
145: /**
146: * Set the boolean value that marks a dependency as required
147: * <p>For example if using 'required=true' (the default),
148: * this value should be <code>true</code>; but if using
149: * 'optional=false', this value should be <code>false</code>.
150: * @see #setRequiredParameterName(String)
151: */
152: public void setRequiredParameterValue(boolean requiredParameterValue) {
153: this .requiredParameterValue = requiredParameterValue;
154: }
155:
156: public void setOrder(int order) {
157: this .order = order;
158: }
159:
160: public int getOrder() {
161: return this .order;
162: }
163:
164: public void setBeanFactory(BeanFactory beanFactory)
165: throws BeansException {
166: if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
167: throw new IllegalArgumentException(
168: "AutowiredAnnotationBeanPostProcessor requires a ConfigurableListableBeanFactory");
169: }
170: this .beanFactory = (ConfigurableListableBeanFactory) beanFactory;
171: }
172:
173: public Constructor[] determineCandidateConstructors(
174: Class beanClass, String beanName) throws BeansException {
175: // Quick check on the concurrent map first, with minimal locking.
176: Constructor[] candidateConstructors = this .candidateConstructorsCache
177: .get(beanClass);
178: if (candidateConstructors == null) {
179: synchronized (this .candidateConstructorsCache) {
180: candidateConstructors = this .candidateConstructorsCache
181: .get(beanClass);
182: if (candidateConstructors == null) {
183: Constructor[] rawCandidates = beanClass
184: .getDeclaredConstructors();
185: List<Constructor> candidates = new ArrayList<Constructor>(
186: rawCandidates.length);
187: Constructor requiredConstructor = null;
188: Constructor defaultConstructor = null;
189: for (int i = 0; i < rawCandidates.length; i++) {
190: Constructor<?> candidate = rawCandidates[i];
191: Annotation annotation = candidate
192: .getAnnotation(getAutowiredAnnotationType());
193: if (annotation != null) {
194: if (requiredConstructor != null) {
195: throw new BeanCreationException(
196: "Invalid autowire-marked constructor: "
197: + candidate
198: + ". Found another constructor with 'required' Autowired annotation: "
199: + requiredConstructor);
200: }
201: if (candidate.getParameterTypes().length == 0) {
202: throw new IllegalStateException(
203: "Autowired annotation requires at least one argument: "
204: + candidate);
205: }
206: boolean required = determineRequiredStatus(annotation);
207: if (required) {
208: if (!candidates.isEmpty()) {
209: throw new BeanCreationException(
210: "Invalid autowire-marked constructors: "
211: + candidates
212: + ". Found another constructor with 'required' Autowired annotation: "
213: + requiredConstructor);
214: }
215: requiredConstructor = candidate;
216: }
217: candidates.add(candidate);
218: } else if (candidate.getParameterTypes().length == 0) {
219: defaultConstructor = candidate;
220: }
221: }
222: if (!candidates.isEmpty()) {
223: // Add default constructor to list of optional constructors, as fallback.
224: if (requiredConstructor == null
225: && defaultConstructor != null) {
226: candidates.add(defaultConstructor);
227: }
228: candidateConstructors = (Constructor[]) candidates
229: .toArray(new Constructor[candidates
230: .size()]);
231: } else {
232: candidateConstructors = new Constructor[0];
233: }
234: this .candidateConstructorsCache.put(beanClass,
235: candidateConstructors);
236: }
237: }
238: }
239: return (candidateConstructors.length > 0 ? candidateConstructors
240: : null);
241: }
242:
243: public boolean postProcessAfterInstantiation(Object bean,
244: String beanName) throws BeansException {
245: InjectionMetadata metadata = findAutowiringMetadata(bean
246: .getClass());
247: try {
248: metadata.injectFields(bean, beanName);
249: } catch (Throwable ex) {
250: throw new BeanCreationException(beanName,
251: "Autowiring of fields failed", ex);
252: }
253: return true;
254: }
255:
256: public PropertyValues postProcessPropertyValues(PropertyValues pvs,
257: PropertyDescriptor[] pds, Object bean, String beanName)
258: throws BeansException {
259:
260: InjectionMetadata metadata = findAutowiringMetadata(bean
261: .getClass());
262: try {
263: metadata.injectMethods(bean, beanName, pvs);
264: } catch (Throwable ex) {
265: throw new BeanCreationException(beanName,
266: "Autowiring of methods failed", ex);
267: }
268: return pvs;
269: }
270:
271: private InjectionMetadata findAutowiringMetadata(final Class clazz) {
272: // Quick check on the concurrent map first, with minimal locking.
273: InjectionMetadata metadata = this .injectionMetadataCache
274: .get(clazz);
275: if (metadata == null) {
276: synchronized (this .injectionMetadataCache) {
277: metadata = this .injectionMetadataCache.get(clazz);
278: if (metadata == null) {
279: final InjectionMetadata newMetadata = new InjectionMetadata();
280: ReflectionUtils.doWithFields(clazz,
281: new ReflectionUtils.FieldCallback() {
282: public void doWith(Field field) {
283: Annotation annotation = field
284: .getAnnotation(getAutowiredAnnotationType());
285: if (annotation != null) {
286: if (Modifier.isStatic(field
287: .getModifiers())) {
288: throw new IllegalStateException(
289: "Autowired annotation is not supported on static fields");
290: }
291: boolean required = determineRequiredStatus(annotation);
292: newMetadata
293: .addInjectedField(new AutowiredElement(
294: field,
295: required, null));
296: }
297: }
298: });
299: ReflectionUtils.doWithMethods(clazz,
300: new ReflectionUtils.MethodCallback() {
301: public void doWith(Method method) {
302: Annotation annotation = method
303: .getAnnotation(getAutowiredAnnotationType());
304: if (annotation != null) {
305: if (Modifier.isStatic(method
306: .getModifiers())) {
307: throw new IllegalStateException(
308: "Autowired annotation is not supported on static methods");
309: }
310: if (method.getParameterTypes().length == 0) {
311: throw new IllegalStateException(
312: "Autowired annotation requires at least one argument: "
313: + method);
314: }
315: boolean required = determineRequiredStatus(annotation);
316: PropertyDescriptor pd = BeanUtils
317: .findPropertyForMethod(method);
318: newMetadata
319: .addInjectedMethod(new AutowiredElement(
320: method,
321: required, pd));
322: }
323: }
324: });
325: metadata = newMetadata;
326: this .injectionMetadataCache.put(clazz, metadata);
327: }
328: }
329: }
330: return metadata;
331: }
332:
333: /**
334: * Obtain all beans of the given type as autowire candidates.
335: * @param type the type of the bean
336: * @return the target beans, or an empty Collection if no bean of this type is found
337: * @throws BeansException if bean retrieval failed
338: */
339: protected Map findAutowireCandidates(Class type)
340: throws BeansException {
341: if (this .beanFactory == null) {
342: throw new IllegalStateException(
343: "No BeanFactory configured - "
344: + "override the getBeanOfType method or specify the 'beanFactory' property");
345: }
346: return BeanFactoryUtils.beansOfTypeIncludingAncestors(
347: this .beanFactory, type);
348: }
349:
350: /**
351: * Determine if the annotated field or method requires its dependency.
352: * <p>A 'required' dependency means that autowiring should fail when no beans
353: * are found. Otherwise, the autowiring process will simply bypass the field
354: * or method when no beans are found.
355: * @param annotation the Autowired annotation
356: * @return whether the annotation indicates that a dependency is required
357: */
358: protected boolean determineRequiredStatus(Annotation annotation) {
359: try {
360: Method method = ReflectionUtils.findMethod(annotation
361: .annotationType(), this .requiredParameterName);
362: return (this .requiredParameterValue == (Boolean) ReflectionUtils
363: .invokeMethod(method, annotation));
364: } catch (Exception ex) {
365: // required by default
366: return true;
367: }
368: }
369:
370: /**
371: * Class representing injection information about an annotated field
372: * or setter method.
373: */
374: private class AutowiredElement extends
375: InjectionMetadata.InjectedElement {
376:
377: private final boolean required;
378:
379: private volatile String beanNameForField;
380:
381: private volatile String[] beanNamesForMethod;
382:
383: public AutowiredElement(Member member, boolean required,
384: PropertyDescriptor pd) {
385: super (member, pd);
386: this .required = required;
387: }
388:
389: @Override
390: protected void inject(Object bean, String beanName,
391: PropertyValues pvs) throws Throwable {
392: if (this .skip) {
393: return;
394: }
395: if (this .isField) {
396: Field field = (Field) this .member;
397: try {
398: Object argument = null;
399: String determinedBeanName = this .beanNameForField;
400: if (determinedBeanName != null) {
401: argument = beanFactory
402: .getBean(determinedBeanName);
403: } else {
404: Set<String> autowiredBeanNames = new LinkedHashSet<String>(
405: 4);
406: TypeConverter typeConverter = beanFactory
407: .getTypeConverter();
408: argument = beanFactory.resolveDependency(
409: new DependencyDescriptor(field,
410: this .required), beanName,
411: autowiredBeanNames, typeConverter);
412: registerDependentBeans(beanName,
413: autowiredBeanNames);
414: if (autowiredBeanNames.size() == 1) {
415: this .beanNameForField = autowiredBeanNames
416: .iterator().next();
417: }
418: }
419: if (argument != null) {
420: ReflectionUtils.makeAccessible(field);
421: field.set(bean, argument);
422: }
423: } catch (Throwable ex) {
424: throw new BeanCreationException(
425: "Could not autowire field: " + field, ex);
426: }
427: } else {
428: if (this .pd != null && pvs != null
429: && pvs.contains(this .pd.getName())) {
430: // Explicit value provided as part of the bean definition.
431: this .skip = true;
432: return;
433: }
434: Method method = (Method) this .member;
435: Object[] arguments = new Object[method
436: .getParameterTypes().length];
437: try {
438: String[] determinedBeanNames = this .beanNamesForMethod;
439: if (determinedBeanNames != null) {
440: for (int i = 0; i < determinedBeanNames.length; i++) {
441: arguments[i] = beanFactory
442: .getBean(determinedBeanNames[i]);
443: }
444: } else {
445: Set<String> autowiredBeanNames = new LinkedHashSet<String>(
446: 4);
447: TypeConverter typeConverter = beanFactory
448: .getTypeConverter();
449: for (int i = 0; i < arguments.length; i++) {
450: arguments[i] = beanFactory
451: .resolveDependency(
452: new DependencyDescriptor(
453: new MethodParameter(
454: method, i),
455: this .required),
456: beanName,
457: autowiredBeanNames,
458: typeConverter);
459: if (arguments[i] == null) {
460: arguments = null;
461: break;
462: }
463: }
464: if (arguments != null) {
465: registerDependentBeans(beanName,
466: autowiredBeanNames);
467: if (autowiredBeanNames.size() == arguments.length) {
468: this .beanNamesForMethod = autowiredBeanNames
469: .toArray(new String[arguments.length]);
470: }
471: }
472: }
473: if (arguments != null) {
474: ReflectionUtils.makeAccessible(method);
475: method.invoke(bean, arguments);
476: }
477: } catch (InvocationTargetException ex) {
478: throw ex.getTargetException();
479: } catch (Throwable ex) {
480: throw new BeanCreationException(
481: "Could not autowire method: " + method, ex);
482: }
483: }
484: }
485:
486: private void registerDependentBeans(String beanName,
487: Set<String> autowiredBeanNames) {
488: for (Iterator it = autowiredBeanNames.iterator(); it
489: .hasNext();) {
490: String autowiredBeanName = (String) it.next();
491: beanFactory.registerDependentBean(autowiredBeanName,
492: beanName);
493: if (logger.isDebugEnabled()) {
494: logger.debug("Autowiring by type from bean name '"
495: + beanName
496: + "' via "
497: + (this .isField ? "field"
498: : "configuration method")
499: + " to bean named '" + autowiredBeanName
500: + "'");
501: }
502: }
503: }
504: }
505:
506: }
|