View Javadoc

1   package com.bm.introspectors;
2   
3   import java.beans.PropertyDescriptor;
4   import java.lang.annotation.Annotation;
5   import java.lang.reflect.Field;
6   import java.lang.reflect.InvocationTargetException;
7   import java.lang.reflect.Method;
8   import java.lang.reflect.ParameterizedType;
9   import java.lang.reflect.Type;
10  
11  import org.apache.commons.beanutils.PropertyUtils;
12  import org.apache.commons.lang.builder.EqualsBuilder;
13  import org.apache.commons.lang.builder.HashCodeBuilder;
14  
15  
16  import com.bm.ejb3metadata.annotations.metadata.FieldAnnotationMetadata;
17  import com.bm.utils.Ejb3Utils;
18  
19  /**
20   * Every persistent property of a EJB3 entity bean can be defined as field
21   * access or method access (using setter/getters). The property class abstracts
22   * from the access method and represtets a field (AccessType.FIELD) OR
23   * getter/setter (AccessType.PROPERTY)
24   * 
25   * @author Daniel Wiese
26   * 
27   */
28  public class Property {
29  
30  	private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(Property.class);
31  
32  	private final String propertyName;
33  
34  	private final Field fieldName;
35  
36  	private final PropertyDescriptor property;
37  
38  	private final Class declaringClass;
39  
40  	private final boolean accessTypeField;
41  
42  	/**
43  	 * Contructor using getter/setter access.
44  	 * 
45  	 * @param declaringClass -
46  	 *            the class wich declares the property
47  	 * 
48  	 * @param property -
49  	 *            the property descriptor
50  	 */
51  	public Property(Class declaringClass, PropertyDescriptor property) {
52  		this.propertyName = property.getName();
53  		this.property = property;
54  		this.fieldName = null;
55  		this.accessTypeField = false;
56  		this.declaringClass = declaringClass;
57  	}
58  
59  	/**
60  	 * Contructor using field access. Ejb3 metadata is passed directly.
61  	 * 
62  	 * @param metaData
63  	 *            the ejb3 metadata information
64  	 * 
65  	 */
66  	public Property(FieldAnnotationMetadata metaData) {
67  		this.propertyName = metaData.getFieldName();
68  		this.property = null;
69  		this.accessTypeField = true;
70  		try {
71  			this.declaringClass = Thread.currentThread()
72  					.getContextClassLoader().loadClass(
73  							metaData.getClassAnnotationMetadata()
74  									.getClassName().replace('/', '.'));
75  		} catch (ClassNotFoundException e) {
76  			throw new RuntimeException("The class ("
77  					+ metaData.getClassAnnotationMetadata().getClassName()
78  					+ ") was not found");
79  		}
80  
81  		try {
82  			this.fieldName = this.declaringClass
83  					.getDeclaredField(this.propertyName);
84  		} catch (SecurityException e) {
85  			throw new RuntimeException("The field (" + this.propertyName
86  					+ ") in Class  ("
87  					+ metaData.getClassAnnotationMetadata().getClassName()
88  					+ ") was not found");
89  		} catch (NoSuchFieldException e) {
90  			throw new RuntimeException("The field (" + this.propertyName
91  					+ ") in Class  ("
92  					+ metaData.getClassAnnotationMetadata().getClassName()
93  					+ ") was not found");
94  		}
95  	}
96  
97  	/**
98  	 * Contructor uing field access.
99  	 * 
100 	 * @param fieldName -
101 	 *            der name des feldes
102 	 */
103 	public Property(Field fieldName) {
104 		this.propertyName = fieldName.getName();
105 		this.fieldName = fieldName;
106 		this.property = null;
107 		this.accessTypeField = true;
108 		this.declaringClass = fieldName.getDeclaringClass();
109 	}
110 
111 	/**
112 	 * Sets a value of the field / getterMethod.
113 	 * 
114 	 * @author Daniel Wiese
115 	 * @param instance -
116 	 *            the instance (Typed)
117 	 * @param value -
118 	 *            the new value
119 	 * @throws IllegalAccessException -
120 	 *             in error case
121 	 */
122 	public void setField(Object instance, Object value)
123 			throws IllegalAccessException {
124 		try {
125 			if (this.accessTypeField) {
126 				// access type property
127 				if (!this.fieldName.isAccessible()) {
128 					this.fieldName.setAccessible(true);
129 					this.fieldName.set(instance, value);
130 					this.fieldName.setAccessible(false);
131 				} else {
132 					this.fieldName.set(instance, value);
133 				}
134 			} else {
135 				try {
136 					// acces type property
137 					PropertyUtils.setProperty(instance, this.propertyName,
138 							value);
139 				} catch (InvocationTargetException e) {
140 					log.error("Can¥t set the value (" + value
141 							+ ") in property: " + this.propertyName);
142 					throw new IllegalAccessException(
143 							"Can¥t invoke the setter method set"
144 									+ this.propertyName);
145 				} catch (NoSuchMethodException e) {
146 					log.error("Can¥t set the value (" + value
147 							+ ") in property: " + this.propertyName);
148 					throw new IllegalAccessException(
149 							"Can¥t invoke the setter method set"
150 									+ this.propertyName);
151 				} catch (IllegalArgumentException e) {
152 					log.error("Can¥t set the value (" + value
153 							+ ") in property: " + this.propertyName);
154 					throw e;
155 				}
156 			}
157 		} catch (IllegalAccessException ex) {
158 			log.error("Can¥t set the value (" + value + ") in property: "
159 					+ this.propertyName, ex);
160 			throw ex;
161 		} catch (RuntimeException ruex) {
162 
163 			log.error("Can¥t set the value (" + value + ") in property: "
164 					+ this.propertyName, ruex);
165 			throw ruex;
166 
167 		}
168 	}
169 
170 	/**
171 	 * Returns a value of an field.
172 	 * 
173 	 * @author Daniel Wiese
174 	 * @param instance -
175 	 *            the instance
176 	 * @return - the value of the paremeter of the instance
177 	 * @throws IllegalAccessException -
178 	 *             in error case
179 	 */
180 	public Object getField(Object instance) throws IllegalAccessException {
181 		Object back = null;
182 		if (this.accessTypeField) {
183 			// access type property
184 			if (!this.fieldName.isAccessible()) {
185 				this.fieldName.setAccessible(true);
186 				back = this.fieldName.get(instance);
187 				this.fieldName.setAccessible(false);
188 			} else {
189 				back = this.fieldName.get(instance);
190 			}
191 		} else {
192 			try {
193 				// acces type property
194 				back = PropertyUtils.getProperty(instance, this.propertyName);
195 			} catch (InvocationTargetException e) {
196 				throw new IllegalAccessException(
197 						"Can¥t invoke the getter method get"
198 								+ this.propertyName);
199 			} catch (NoSuchMethodException e) {
200 				throw new IllegalAccessException(
201 						"Can¥t invoke the getter method get"
202 								+ this.propertyName);
203 			}
204 		}
205 		return back;
206 	}
207 
208 	/**
209 	 * Returns the type of the property.
210 	 * 
211 	 * @return - the type
212 	 */
213 	public Class getType() {
214 		if (this.accessTypeField) {
215 			return this.fieldName.getType();
216 		}
217 		final Method method = this.property.getReadMethod();
218 		return method.getReturnType();
219 
220 	}
221 
222 	/**
223 	 * Returns the generic Type of this property. E.g. id the proprty is.
224 	 * Collection/Order/ then Order will be returned.
225 	 * 
226 	 * @author Daniel Wiese
227 	 * @since 28.10.2005
228 	 * @return the generic Type of this property
229 	 */
230 	public Type getGenericType() {
231 		if (this.accessTypeField) {
232 			return this.fieldName.getGenericType();
233 		}
234 		final Method methodToFind = this.property.getReadMethod();
235 		return methodToFind.getGenericReturnType();
236 	}
237 
238 	/**
239 	 * If the propety represents a genericType (e.g. Collection/Order/) ! Typed
240 	 * class thit ONE type) -> then the type is returned.
241 	 * 
242 	 * @return - the type of the typed class or null
243 	 */
244 	@SuppressWarnings("unchecked")
245 	public Class<Object> getGenericTypeClass() {
246 		if (this.getGenericType() instanceof ParameterizedType) {
247 			final ParameterizedType type = (ParameterizedType) this
248 					.getGenericType();
249 			if (type.getActualTypeArguments().length == 1) {
250 				Class<Object> ty = (Class<Object>) type
251 						.getActualTypeArguments()[0];
252 				return ty;
253 			}
254 		}
255 		return null;
256 	}
257 
258 	/**
259 	 * Return the name.
260 	 * 
261 	 * @return - the name
262 	 */
263 	public String getName() {
264 		return this.propertyName;
265 	}
266 
267 	/**
268 	 * Returns the class where the property is declared.
269 	 * 
270 	 * @return Returns the declaringClass.
271 	 */
272 	public Class getDeclaringClass() {
273 		return this.declaringClass;
274 	}
275 
276 	/**
277 	 * Equals.
278 	 * 
279 	 * @param other
280 	 *            the other to compare
281 	 * @return - true if equal
282 	 * @see java.lang.Object#equals(java.lang.Object)
283 	 */
284 	@Override
285 	public boolean equals(Object other) {
286 		if (other instanceof Property) {
287 			final Property otherC = (Property) other;
288 			final EqualsBuilder eqBuilder = new EqualsBuilder();
289 			eqBuilder.append(this.accessTypeField, otherC.accessTypeField);
290 			eqBuilder.append(this.fieldName, otherC.fieldName);
291 			eqBuilder.append(this.property, otherC.property);
292 			return eqBuilder.isEquals();
293 
294 		}
295 		return false;
296 	}
297 
298 	/**
299 	 * Hash Code.
300 	 * 
301 	 * @return the hash code
302 	 * @see java.lang.Object#hashCode()
303 	 */
304 	@Override
305 	public int hashCode() {
306 		final HashCodeBuilder hcBuilder = new HashCodeBuilder(3, 17);
307 		hcBuilder.append(this.accessTypeField);
308 		hcBuilder.append(this.fieldName);
309 		hcBuilder.append(this.property);
310 		return hcBuilder.toHashCode();
311 	}
312 
313 	/**
314 	 * Returns the property.
315 	 * 
316 	 * @return Returns the property.
317 	 */
318 	public PropertyDescriptor getProperty() {
319 		return property;
320 	}
321 
322 	/**
323 	 * Returns null if the accestype is field.
324 	 * 
325 	 * @return Returns the propertyName.
326 	 */
327 	public String getPropertyName() {
328 		return propertyName;
329 	}
330 
331 	/**
332 	 * Returns a annotation for the current property if present.
333 	 * 
334 	 * @param <T>
335 	 *            the annotation type.
336 	 * @param annnotation
337 	 *            the annotation class
338 	 * @return the annotation instance
339 	 */
340 	public <T extends Annotation> T getAnnotation(Class<T> annnotation) {
341 		if (this.accessTypeField) {
342 			return this.fieldName.getAnnotation(annnotation);
343 		}
344 		return this.property.getReadMethod().getAnnotation(annnotation);
345 	}
346 
347 	/**
348 	 * To String.
349 	 * 
350 	 * @return - formatted string
351 	 * @see java.lang.Object#toString()
352 	 */
353 	@Override
354 	public String toString() {
355 		final StringBuilder sb = new StringBuilder();
356 		sb.append("Declared in Class: (").append(
357 				Ejb3Utils.getShortClassName(this.getDeclaringClass())).append(
358 				") Prop.Name: (").append(this.propertyName)
359 				.append(") - Type (").append(
360 						Ejb3Utils.getShortClassName(this.getType()))
361 				.append(")");
362 		return sb.toString();
363 	}
364 }