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.reflect.Field;
021: import java.lang.reflect.InvocationTargetException;
022: import java.lang.reflect.Member;
023: import java.lang.reflect.Method;
024: import java.util.Arrays;
025: import java.util.LinkedHashSet;
026: import java.util.Set;
027:
028: import org.springframework.beans.PropertyValues;
029: import org.springframework.util.ReflectionUtils;
030:
031: /**
032: * Internal class for managing injection metadata.
033: * Not intended for direct use in applications.
034: *
035: * <p>Used by {@link AutowiredAnnotationBeanPostProcessor},
036: * {@link org.springframework.context.annotation.CommonAnnotationBeanPostProcessor} and
037: * {@link org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor}.
038: *
039: * @author Juergen Hoeller
040: * @since 2.5
041: */
042: public class InjectionMetadata {
043:
044: private Set<InjectedElement> resourceFields = new LinkedHashSet<InjectedElement>();
045:
046: private Set<InjectedElement> resourceMethods = new LinkedHashSet<InjectedElement>();
047:
048: public void addInjectedField(InjectedElement element) {
049: this .resourceFields.add(element);
050: }
051:
052: public void addInjectedMethod(InjectedElement element) {
053: this .resourceMethods.add(element);
054: }
055:
056: public void injectFields(Object target, String beanName)
057: throws Throwable {
058: if (!this .resourceFields.isEmpty()) {
059: for (InjectedElement element : this .resourceFields) {
060: element.inject(target, beanName, null);
061: }
062: }
063: }
064:
065: public void injectMethods(Object target, String beanName,
066: PropertyValues pvs) throws Throwable {
067: if (!this .resourceMethods.isEmpty()) {
068: for (InjectedElement element : this .resourceMethods) {
069: element.inject(target, beanName, pvs);
070: }
071: }
072: }
073:
074: public static abstract class InjectedElement {
075:
076: protected final Member member;
077:
078: protected final boolean isField;
079:
080: protected final PropertyDescriptor pd;
081:
082: protected volatile boolean skip = false;
083:
084: protected InjectedElement(Member member, PropertyDescriptor pd) {
085: this .member = member;
086: this .isField = (member instanceof Field);
087: this .pd = pd;
088: }
089:
090: protected final Class getResourceType() {
091: return (this .isField ? ((Field) this .member).getType()
092: : ((Method) this .member).getParameterTypes()[0]);
093: }
094:
095: protected final void checkResourceType(Class resourceType) {
096: if (this .isField) {
097: Class fieldType = ((Field) this .member).getType();
098: if (!fieldType.isAssignableFrom(resourceType)) {
099: throw new IllegalStateException(
100: "Specified resource type ["
101: + resourceType.getName()
102: + "] is not assignable to field type ["
103: + fieldType + "]");
104: }
105: } else {
106: Class paramType = ((Method) this .member)
107: .getParameterTypes()[0];
108: if (!paramType.isAssignableFrom(resourceType)) {
109: throw new IllegalStateException(
110: "Specified resource type ["
111: + resourceType.getName()
112: + "] is not assignable to method parameter type ["
113: + paramType + "]");
114: }
115: }
116: }
117:
118: /**
119: * Either this or {@link #getResourceToInject} needs to be overridden.
120: */
121: protected void inject(Object target, String requestingBeanName,
122: PropertyValues pvs) throws Throwable {
123: if (this .skip) {
124: return;
125: }
126: if (this .isField) {
127: Field field = (Field) this .member;
128: ReflectionUtils.makeAccessible(field);
129: field.set(target, getResourceToInject(target,
130: requestingBeanName));
131: } else {
132: if (this .pd != null && pvs != null
133: && pvs.contains(this .pd.getName())) {
134: // Explicit value provided as part of the bean definition.
135: this .skip = true;
136: return;
137: }
138: try {
139: Method method = (Method) this .member;
140: ReflectionUtils.makeAccessible(method);
141: method.invoke(target, getResourceToInject(target,
142: requestingBeanName));
143: } catch (InvocationTargetException ex) {
144: throw ex.getTargetException();
145: }
146: }
147: }
148:
149: /**
150: * Either this or {@link #inject} needs to be overridden.
151: */
152: protected Object getResourceToInject(Object target,
153: String requestingBeanName) {
154: return null;
155: }
156:
157: public boolean equals(Object other) {
158: if (this == other) {
159: return true;
160: }
161: if (!(other instanceof InjectedElement)) {
162: return false;
163: }
164: InjectedElement otherElement = (InjectedElement) other;
165: if (this .isField) {
166: return this .member.equals(otherElement.member);
167: } else {
168: return (otherElement.member instanceof Method
169: && this .member.getName().equals(
170: otherElement.member.getName()) && Arrays
171: .equals(((Method) this .member)
172: .getParameterTypes(),
173: ((Method) otherElement.member)
174: .getParameterTypes()));
175: }
176: }
177:
178: public int hashCode() {
179: return this .member.getClass().hashCode() * 29
180: + this.member.getName().hashCode();
181: }
182: }
183:
184: }
|