001: package com.bm.introspectors;
002:
003: import java.beans.PropertyDescriptor;
004: import java.lang.annotation.Annotation;
005: import java.lang.reflect.Field;
006: import java.lang.reflect.InvocationTargetException;
007: import java.lang.reflect.Method;
008: import java.lang.reflect.ParameterizedType;
009: import java.lang.reflect.Type;
010:
011: import org.apache.commons.beanutils.PropertyUtils;
012: import org.apache.commons.lang.builder.EqualsBuilder;
013: import org.apache.commons.lang.builder.HashCodeBuilder;
014: import org.apache.log4j.Logger;
015:
016: import com.bm.ejb3metadata.annotations.metadata.FieldAnnotationMetadata;
017: import com.bm.utils.Ejb3Utils;
018:
019: /**
020: * Every persistent property of a EJB3 entity bean can be defined as field
021: * access or method access (using setter/getters). The property class abstracts
022: * from the access method and represtets a field (AccessType.FIELD) OR
023: * getter/setter (AccessType.PROPERTY)
024: *
025: * @author Daniel Wiese
026: *
027: */
028: public class Property {
029:
030: private static final Logger log = Logger.getLogger(Property.class);
031:
032: private final String propertyName;
033:
034: private final Field fieldName;
035:
036: private final PropertyDescriptor property;
037:
038: private final Class declaringClass;
039:
040: private final boolean accessTypeField;
041:
042: /**
043: * Contructor using getter/setter access.
044: *
045: * @param declaringClass -
046: * the class wich declares the property
047: *
048: * @param property -
049: * the property descriptor
050: */
051: public Property(Class declaringClass, PropertyDescriptor property) {
052: this .propertyName = property.getName();
053: this .property = property;
054: this .fieldName = null;
055: this .accessTypeField = false;
056: this .declaringClass = declaringClass;
057: }
058:
059: /**
060: * Contructor using field access. Ejb3 metadata is passed directly.
061: *
062: * @param metaData
063: * the ejb3 metadata information
064: *
065: */
066: public Property(FieldAnnotationMetadata metaData) {
067: this .propertyName = metaData.getFieldName();
068: this .property = null;
069: this .accessTypeField = true;
070: try {
071: this .declaringClass = Thread.currentThread()
072: .getContextClassLoader().loadClass(
073: metaData.getClassAnnotationMetadata()
074: .getClassName().replace('/', '.'));
075: } catch (ClassNotFoundException e) {
076: throw new RuntimeException("The class ("
077: + metaData.getClassAnnotationMetadata()
078: .getClassName() + ") was not found");
079: }
080:
081: try {
082: this .fieldName = this .declaringClass
083: .getDeclaredField(this .propertyName);
084: } catch (SecurityException e) {
085: throw new RuntimeException("The field ("
086: + this .propertyName
087: + ") in Class ("
088: + metaData.getClassAnnotationMetadata()
089: .getClassName() + ") was not found");
090: } catch (NoSuchFieldException e) {
091: throw new RuntimeException("The field ("
092: + this .propertyName
093: + ") in Class ("
094: + metaData.getClassAnnotationMetadata()
095: .getClassName() + ") was not found");
096: }
097: }
098:
099: /**
100: * Contructor uing field access.
101: *
102: * @param fieldName -
103: * der name des feldes
104: */
105: public Property(Field fieldName) {
106: this .propertyName = fieldName.getName();
107: this .fieldName = fieldName;
108: this .property = null;
109: this .accessTypeField = true;
110: this .declaringClass = fieldName.getDeclaringClass();
111: }
112:
113: /**
114: * Sets a value of the field / getterMethod.
115: *
116: * @author Daniel Wiese
117: * @param instance -
118: * the instance (Typed)
119: * @param value -
120: * the new value
121: * @throws IllegalAccessException -
122: * in error case
123: */
124: public void setField(Object instance, Object value)
125: throws IllegalAccessException {
126: try {
127: if (this .accessTypeField) {
128: // access type property
129: if (!this .fieldName.isAccessible()) {
130: this .fieldName.setAccessible(true);
131: this .fieldName.set(instance, value);
132: this .fieldName.setAccessible(false);
133: } else {
134: this .fieldName.set(instance, value);
135: }
136: } else {
137: try {
138: // acces type property
139: PropertyUtils.setProperty(instance,
140: this .propertyName, value);
141: } catch (InvocationTargetException e) {
142: log.error("Canīt set the value (" + value
143: + ") in property: " + this .propertyName);
144: throw new IllegalAccessException(
145: "Canīt invoke the setter method set"
146: + this .propertyName);
147: } catch (NoSuchMethodException e) {
148: log.error("Canīt set the value (" + value
149: + ") in property: " + this .propertyName);
150: throw new IllegalAccessException(
151: "Canīt invoke the setter method set"
152: + this .propertyName);
153: } catch (IllegalArgumentException e) {
154: log.error("Canīt set the value (" + value
155: + ") in property: " + this .propertyName);
156: throw e;
157: }
158: }
159: } catch (IllegalAccessException ex) {
160: log.error("Canīt set the value (" + value
161: + ") in property: " + this .propertyName, ex);
162: throw ex;
163: } catch (RuntimeException ruex) {
164:
165: log.error("Canīt set the value (" + value
166: + ") in property: " + this .propertyName, ruex);
167: throw ruex;
168:
169: }
170: }
171:
172: /**
173: * Returns a value of an field.
174: *
175: * @author Daniel Wiese
176: * @param instance -
177: * the instance
178: * @return - the value of the paremeter of the instance
179: * @throws IllegalAccessException -
180: * in error case
181: */
182: public Object getField(Object instance)
183: throws IllegalAccessException {
184: Object back = null;
185: if (this .accessTypeField) {
186: // access type property
187: if (!this .fieldName.isAccessible()) {
188: this .fieldName.setAccessible(true);
189: back = this .fieldName.get(instance);
190: this .fieldName.setAccessible(false);
191: } else {
192: back = this .fieldName.get(instance);
193: }
194: } else {
195: try {
196: // acces type property
197: back = PropertyUtils.getProperty(instance,
198: this .propertyName);
199: } catch (InvocationTargetException e) {
200: throw new IllegalAccessException(
201: "Canīt invoke the getter method get"
202: + this .propertyName);
203: } catch (NoSuchMethodException e) {
204: throw new IllegalAccessException(
205: "Canīt invoke the getter method get"
206: + this .propertyName);
207: }
208: }
209: return back;
210: }
211:
212: /**
213: * Returns the type of the property.
214: *
215: * @return - the type
216: */
217: public Class getType() {
218: if (this .accessTypeField) {
219: return this .fieldName.getType();
220: }
221: final Method method = this .property.getReadMethod();
222: return method.getReturnType();
223:
224: }
225:
226: /**
227: * Returns the generic Type of this property. E.g. id the proprty is.
228: * Collection/Order/ then Order will be returned.
229: *
230: * @author Daniel Wiese
231: * @since 28.10.2005
232: * @return the generic Type of this property
233: */
234: public Type getGenericType() {
235: if (this .accessTypeField) {
236: return this .fieldName.getGenericType();
237: }
238: final Method methodToFind = this .property.getReadMethod();
239: return methodToFind.getGenericReturnType();
240: }
241:
242: /**
243: * If the propety represents a genericType (e.g. Collection/Order/) ! Typed
244: * class thit ONE type) -> then the type is returned.
245: *
246: * @return - the type of the typed class or null
247: */
248: @SuppressWarnings("unchecked")
249: public Class<Object> getGenericTypeClass() {
250: if (this .getGenericType() instanceof ParameterizedType) {
251: final ParameterizedType type = (ParameterizedType) this
252: .getGenericType();
253: if (type.getActualTypeArguments().length == 1) {
254: Class<Object> ty = (Class<Object>) type
255: .getActualTypeArguments()[0];
256: return ty;
257: }
258: }
259: return null;
260: }
261:
262: /**
263: * Return the name.
264: *
265: * @return - the name
266: */
267: public String getName() {
268: return this .propertyName;
269: }
270:
271: /**
272: * Returns the class where the property is declared.
273: *
274: * @return Returns the declaringClass.
275: */
276: public Class getDeclaringClass() {
277: return this .declaringClass;
278: }
279:
280: /**
281: * Equals.
282: *
283: * @param other
284: * the other to compare
285: * @return - true if equal
286: * @see java.lang.Object#equals(java.lang.Object)
287: */
288: @Override
289: public boolean equals(Object other) {
290: if (other instanceof Property) {
291: final Property otherC = (Property) other;
292: final EqualsBuilder eqBuilder = new EqualsBuilder();
293: eqBuilder.append(this .accessTypeField,
294: otherC.accessTypeField);
295: eqBuilder.append(this .fieldName, otherC.fieldName);
296: eqBuilder.append(this .property, otherC.property);
297: return eqBuilder.isEquals();
298:
299: }
300: return false;
301: }
302:
303: /**
304: * Hash Code.
305: *
306: * @return the hash code
307: * @see java.lang.Object#hashCode()
308: */
309: @Override
310: public int hashCode() {
311: final HashCodeBuilder hcBuilder = new HashCodeBuilder(3, 17);
312: hcBuilder.append(this .accessTypeField);
313: hcBuilder.append(this .fieldName);
314: hcBuilder.append(this .property);
315: return hcBuilder.toHashCode();
316: }
317:
318: /**
319: * Returns the property.
320: *
321: * @return Returns the property.
322: */
323: public PropertyDescriptor getProperty() {
324: return property;
325: }
326:
327: /**
328: * Returns null if the accestype is field.
329: *
330: * @return Returns the propertyName.
331: */
332: public String getPropertyName() {
333: return propertyName;
334: }
335:
336: /**
337: * Returns a annotation for the current property if present.
338: *
339: * @param <T>
340: * the annotation type.
341: * @param annnotation
342: * the annotation class
343: * @return the annotation instance
344: */
345: public <T extends Annotation> T getAnnotation(Class<T> annnotation) {
346: if (this .accessTypeField) {
347: return this .fieldName.getAnnotation(annnotation);
348: }
349: return this .property.getReadMethod().getAnnotation(annnotation);
350: }
351:
352: /**
353: * To String.
354: *
355: * @return - formatted string
356: * @see java.lang.Object#toString()
357: */
358: @Override
359: public String toString() {
360: final StringBuilder sb = new StringBuilder();
361: sb.append("Declared in Class: (").append(
362: Ejb3Utils.getShortClassName(this .getDeclaringClass()))
363: .append(") Prop.Name: (").append(this .propertyName)
364: .append(") - Type (").append(
365: Ejb3Utils.getShortClassName(this .getType()))
366: .append(")");
367: return sb.toString();
368: }
369: }
|