1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.openjpa.enhance;
20
21 import java.lang.reflect.AccessibleObject;
22 import java.lang.reflect.Field;
23 import java.lang.reflect.InvocationTargetException;
24 import java.lang.reflect.Method;
25 import java.lang.reflect.Modifier;
26 import java.security.AccessController;
27
28 import org.apache.commons.lang.StringUtils;
29 import org.apache.openjpa.lib.util.J2DoPrivHelper;
30 import org.apache.openjpa.lib.util.Localizer;
31 import org.apache.openjpa.util.GeneralException;
32 import org.apache.openjpa.util.UserException;
33
34 /**
35 * Reflection utilities used to support and augment enhancement. Used both
36 * at enhancement time and at runtime.
37 *
38 * @author Abe White
39 */
40 public class Reflection {
41
42 private static final Localizer _loc = Localizer.forPackage
43 (Reflection.class);
44
45 /**
46 * Return the getter method matching the given property name, optionally
47 * throwing an exception if none.
48 */
49 public static Method findGetter(Class cls, String prop, boolean mustExist) {
50 prop = StringUtils.capitalize(prop);
51 String name = "get" + prop;
52 Method m;
53 try {
54 // this algorithm searches for a get<prop> or is<prop> method in
55 // a breadth-first manner.
56 for (Class c = cls; c != null && c != Object.class;
57 c = c.getSuperclass()) {
58 m = getDeclaredMethod(c, name, null);
59 if (m != null) {
60 return m;
61 } else {
62 m = getDeclaredMethod(c, "is" + prop, null);
63 if (m != null && (m.getReturnType() == boolean.class
64 || m.getReturnType() == Boolean.class))
65 return m;
66 }
67 }
68 } catch (Exception e) {
69 throw new GeneralException(e);
70 }
71
72 if (mustExist)
73 throw new UserException(_loc.get("bad-getter", cls, prop));
74 return null;
75 }
76
77 /**
78 * Return the setter method matching the given property name, optionally
79 * throwing an exception if none. The property must also have a getter.
80 */
81 public static Method findSetter(Class cls, String prop, boolean mustExist) {
82 Method getter = findGetter(cls, prop, mustExist);
83 return (getter == null) ? null
84 : findSetter(cls, prop, getter.getReturnType(), mustExist);
85 }
86
87 /**
88 * Return the setter method matching the given property name, optionally
89 * throwing an exception if none.
90 */
91 public static Method findSetter(Class cls, String prop, Class param,
92 boolean mustExist) {
93 String name = "set" + StringUtils.capitalize(prop);
94 Method m;
95 try {
96 for (Class c = cls; c != null && c != Object.class;
97 c = c.getSuperclass()) {
98 m = getDeclaredMethod(c, name, param);
99 if (m != null)
100 return m;
101 }
102 } catch (Exception e) {
103 throw new GeneralException(e);
104 }
105
106 if (mustExist)
107 throw new UserException(_loc.get("bad-setter", cls, prop));
108 return null;
109 }
110
111 /**
112 * Invokes <code>cls.getDeclaredMethods()</code>, and returns the method
113 * that matches the <code>name</code> and <code>param</code> arguments.
114 * Avoids the exception thrown by <code>Class.getDeclaredMethod()</code>
115 * for performance reasons. <code>param</code> may be null. Additionally,
116 * if there are multiple methods with different return types, this will
117 * return the method defined in the least-derived class.
118 *
119 * @since 0.9.8
120 */
121 static Method getDeclaredMethod(Class cls, String name,
122 Class param) {
123 Method[] methods = (Method[]) AccessController.doPrivileged(
124 J2DoPrivHelper.getDeclaredMethodsAction(cls));
125 Method candidate = null;
126 for (int i = 0 ; i < methods.length; i++) {
127 if (name.equals(methods[i].getName())) {
128 Class[] methodParams = methods[i].getParameterTypes();
129 if (param == null && methodParams.length == 0)
130 candidate = mostDerived(methods[i], candidate);
131 else if (param != null && methodParams.length == 1
132 && param.equals(methodParams[0]))
133 candidate = mostDerived(methods[i], candidate);
134 }
135 }
136 return candidate;
137 }
138
139 static Method mostDerived(Method meth1, Method meth2) {
140 if (meth1 == null)
141 return meth2;
142 if (meth2 == null)
143 return meth1;
144
145 Class cls2 = meth2.getDeclaringClass();
146 Class cls1 = meth1.getDeclaringClass();
147
148 if (cls1.equals(cls2)) {
149 Class ret1 = meth1.getReturnType();
150 Class ret2 = meth2.getReturnType();
151 if (ret1.isAssignableFrom(ret2))
152 return meth2;
153 else if (ret2.isAssignableFrom(ret1))
154 return meth1;
155 else
156 throw new IllegalArgumentException(
157 _loc.get("most-derived-unrelated-same-type", meth1, meth2)
158 .getMessage());
159 } else {
160 if (cls1.isAssignableFrom(cls2))
161 return meth2;
162 else if (cls2.isAssignableFrom(cls1))
163 return meth1;
164 else
165 throw new IllegalArgumentException(
166 _loc.get("most-derived-unrelated", meth1, meth2)
167 .getMessage());
168 }
169 }
170
171 /**
172 * Return the field with the given name, optionally throwing an exception
173 * if none.
174 */
175 public static Field findField(Class cls, String name, boolean mustExist) {
176 try {
177 Field f;
178 for (Class c = cls; c != null && c != Object.class;
179 c = c.getSuperclass()) {
180 f = getDeclaredField(c, name);
181 if (f != null)
182 return f;
183 }
184 } catch (Exception e) {
185 throw new GeneralException(e);
186 }
187
188 if (mustExist)
189 throw new UserException(_loc.get("bad-field", cls, name));
190 return null;
191 }
192
193 /**
194 * Invokes <code>cls.getDeclaredFields()</code>, and returns the field
195 * that matches the <code>name</code> argument. Avoids the exception
196 * thrown by <code>Class.getDeclaredField()</code> for performance reasons.
197 *
198 * @since 0.9.8
199 */
200 private static Field getDeclaredField(Class cls, String name) {
201 Field[] fields = (Field[]) AccessController.doPrivileged(
202 J2DoPrivHelper.getDeclaredFieldsAction(cls));
203 for (int i = 0 ; i < fields.length; i++) {
204 if (name.equals(fields[i].getName()))
205 return fields[i];
206 }
207 return null;
208 }
209
210 /**
211 * Return the value of the given field in the given object.
212 */
213 public static Object get(Object target, Field field) {
214 if (target == null || field == null)
215 return null;
216 makeAccessible(field, field.getModifiers());
217 try {
218 return field.get(target);
219 } catch (Throwable t) {
220 throw wrapReflectionException(t);
221 }
222 }
223
224 /**
225 * Make the given member accessible if it isn't already.
226 */
227 private static void makeAccessible(AccessibleObject ao, int mods) {
228 try {
229 if (!Modifier.isPublic(mods) && !ao.isAccessible())
230 AccessController.doPrivileged(J2DoPrivHelper
231 .setAccessibleAction(ao, true));
232 } catch (SecurityException se) {
233 throw new UserException(_loc.get("reflect-security", ao)).
234 setFatal(true);
235 }
236 }
237
238 /**
239 * Wrap the given reflection exception as a runtime exception.
240 */
241 private static RuntimeException wrapReflectionException(Throwable t) {
242 if (t instanceof InvocationTargetException)
243 t = ((InvocationTargetException) t).getTargetException();
244 if (t instanceof RuntimeException)
245 return (RuntimeException) t;
246 return new GeneralException(t);
247 }
248
249 /**
250 * Return the value of the given field in the given object.
251 */
252 public static boolean getBoolean(Object target, Field field) {
253 if (target == null || field == null)
254 return false;
255 makeAccessible(field, field.getModifiers());
256 try {
257 return field.getBoolean(target);
258 } catch (Throwable t) {
259 throw wrapReflectionException(t);
260 }
261 }
262
263 /**
264 * Return the value of the given field in the given object.
265 */
266 public static byte getByte(Object target, Field field) {
267 if (target == null || field == null)
268 return (byte) 0;
269 makeAccessible(field, field.getModifiers());
270 try {
271 return field.getByte(target);
272 } catch (Throwable t) {
273 throw wrapReflectionException(t);
274 }
275 }
276
277 /**
278 * Return the value of the given field in the given object.
279 */
280 public static char getChar(Object target, Field field) {
281 if (target == null || field == null)
282 return (char) 0;
283 makeAccessible(field, field.getModifiers());
284 try {
285 return field.getChar(target);
286 } catch (Throwable t) {
287 throw wrapReflectionException(t);
288 }
289 }
290
291 /**
292 * Return the value of the given field in the given object.
293 */
294 public static double getDouble(Object target, Field field) {
295 if (target == null || field == null)
296 return 0D;
297 makeAccessible(field, field.getModifiers());
298 try {
299 return field.getDouble(target);
300 } catch (Throwable t) {
301 throw wrapReflectionException(t);
302 }
303 }
304
305 /**
306 * Return the value of the given field in the given object.
307 */
308 public static float getFloat(Object target, Field field) {
309 if (target == null || field == null)
310 return 0F;
311 makeAccessible(field, field.getModifiers());
312 try {
313 return field.getFloat(target);
314 } catch (Throwable t) {
315 throw wrapReflectionException(t);
316 }
317 }
318
319 /**
320 * Return the value of the given field in the given object.
321 */
322 public static int getInt(Object target, Field field) {
323 if (target == null || field == null)
324 return 0;
325 makeAccessible(field, field.getModifiers());
326 try {
327 return field.getInt(target);
328 } catch (Throwable t) {
329 throw wrapReflectionException(t);
330 }
331 }
332
333 /**
334 * Return the value of the given field in the given object.
335 */
336 public static long getLong(Object target, Field field) {
337 if (target == null || field == null)
338 return 0L;
339 makeAccessible(field, field.getModifiers());
340 try {
341 return field.getLong(target);
342 } catch (Throwable t) {
343 throw wrapReflectionException(t);
344 }
345 }
346
347 /**
348 * Return the value of the given field in the given object.
349 */
350 public static short getShort(Object target, Field field) {
351 if (target == null || field == null)
352 return (short) 0;
353 makeAccessible(field, field.getModifiers());
354 try {
355 return field.getShort(target);
356 } catch (Throwable t) {
357 throw wrapReflectionException(t);
358 }
359 }
360
361 /**
362 * Return the return value of the given getter in the given object.
363 */
364 public static Object get(Object target, Method getter) {
365 if (target == null || getter == null)
366 return null;
367 makeAccessible(getter, getter.getModifiers());
368 try {
369 return getter.invoke(target, (Object[]) null);
370 } catch (Throwable t) {
371 throw wrapReflectionException(t);
372 }
373 }
374
375 /**
376 * Return the return value of the given getter in the given object.
377 */
378 public static boolean getBoolean(Object target, Method getter) {
379 Object o = get(target, getter);
380 return (o == null) ? false : ((Boolean) o).booleanValue();
381 }
382
383 /**
384 * Return the return value of the given getter in the given object.
385 */
386 public static byte getByte(Object target, Method getter) {
387 Object o = get(target, getter);
388 return (o == null) ? (byte) 0 : ((Number) o).byteValue();
389 }
390
391 /**
392 * Return the return value of the given getter in the given object.
393 */
394 public static char getChar(Object target, Method getter) {
395 Object o = get(target, getter);
396 return (o == null) ? (char) 0 : ((Character) o).charValue();
397 }
398
399 /**
400 * Return the return value of the given getter in the given object.
401 */
402 public static double getDouble(Object target, Method getter) {
403 Object o = get(target, getter);
404 return (o == null) ? 0D : ((Number) o).doubleValue();
405 }
406
407 /**
408 * Return the return value of the given getter in the given object.
409 */
410 public static float getFloat(Object target, Method getter) {
411 Object o = get(target, getter);
412 return (o == null) ? 0F : ((Number) o).floatValue();
413 }
414
415 /**
416 * Return the return value of the given getter in the given object.
417 */
418 public static int getInt(Object target, Method getter) {
419 Object o = get(target, getter);
420 return (o == null) ? 0 : ((Number) o).intValue();
421 }
422
423 /**
424 * Return the return value of the given getter in the given object.
425 */
426 public static long getLong(Object target, Method getter) {
427 Object o = get(target, getter);
428 return (o == null) ? 0L : ((Number) o).longValue();
429 }
430
431 /**
432 * Return the return value of the given getter in the given object.
433 */
434 public static short getShort(Object target, Method getter) {
435 Object o = get(target, getter);
436 return (o == null) ? (short) 0 : ((Number) o).shortValue();
437 }
438
439 /**
440 * Set the value of the given field in the given object.
441 */
442 public static void set(Object target, Field field, Object value) {
443 if (target == null || field == null)
444 return;
445 makeAccessible(field, field.getModifiers());
446 try {
447 field.set(target, value);
448 } catch (Throwable t) {
449 throw wrapReflectionException(t);
450 }
451 }
452
453 /**
454 * Set the value of the given field in the given object.
455 */
456 public static void set(Object target, Field field, boolean value) {
457 if (target == null || field == null)
458 return;
459 makeAccessible(field, field.getModifiers());
460 try {
461 field.setBoolean(target, value);
462 } catch (Throwable t) {
463 throw wrapReflectionException(t);
464 }
465 }
466
467 /**
468 * Set the value of the given field in the given object.
469 */
470 public static void set(Object target, Field field, byte value) {
471 if (target == null || field == null)
472 return;
473 makeAccessible(field, field.getModifiers());
474 try {
475 field.setByte(target, value);
476 } catch (Throwable t) {
477 throw wrapReflectionException(t);
478 }
479 }
480
481 /**
482 * Set the value of the given field in the given object.
483 */
484 public static void set(Object target, Field field, char value) {
485 if (target == null || field == null)
486 return;
487 makeAccessible(field, field.getModifiers());
488 try {
489 field.setChar(target, value);
490 } catch (Throwable t) {
491 throw wrapReflectionException(t);
492 }
493 }
494
495 /**
496 * Set the value of the given field in the given object.
497 */
498 public static void set(Object target, Field field, double value) {
499 if (target == null || field == null)
500 return;
501 makeAccessible(field, field.getModifiers());
502 try {
503 field.setDouble(target, value);
504 } catch (Throwable t) {
505 throw wrapReflectionException(t);
506 }
507 }
508
509 /**
510 * Set the value of the given field in the given object.
511 */
512 public static void set(Object target, Field field, float value) {
513 if (target == null || field == null)
514 return;
515 makeAccessible(field, field.getModifiers());
516 try {
517 field.setFloat(target, value);
518 } catch (Throwable t) {
519 throw wrapReflectionException(t);
520 }
521 }
522
523 /**
524 * Set the value of the given field in the given object.
525 */
526 public static void set(Object target, Field field, int value) {
527 if (target == null || field == null)
528 return;
529 makeAccessible(field, field.getModifiers());
530 try {
531 field.setInt(target, value);
532 } catch (Throwable t) {
533 throw wrapReflectionException(t);
534 }
535 }
536
537 /**
538 * Set the value of the given field in the given object.
539 */
540 public static void set(Object target, Field field, long value) {
541 if (target == null || field == null)
542 return;
543 makeAccessible(field, field.getModifiers());
544 try {
545 field.setLong(target, value);
546 } catch (Throwable t) {
547 throw wrapReflectionException(t);
548 }
549 }
550
551 /**
552 * Set the value of the given field in the given object.
553 */
554 public static void set(Object target, Field field, short value) {
555 if (target == null || field == null)
556 return;
557 makeAccessible(field, field.getModifiers());
558 try {
559 field.setShort(target, value);
560 } catch (Throwable t) {
561 throw wrapReflectionException(t);
562 }
563 }
564
565 /**
566 * Set the value of the given field in the given object.
567 * Same behavior as above methods, but parameter ordering is rearranged
568 * to simplify usage from generated bytecodes.
569 *
570 * @since 1.0.0
571 */
572 public static void set(Object target, Object value, Field field) {
573 set(target, field, value);
574 }
575
576 /**
577 * Set the value of the given field in the given object.
578 * Same behavior as above methods, but parameter ordering is rearranged
579 * to simplify usage from generated bytecodes.
580 *
581 * @since 1.0.0
582 */
583 public static void set(Object target, boolean value, Field field) {
584 set(target, field, value);
585 }
586
587 /**
588 * Set the value of the given field in the given object.
589 * Same behavior as above methods, but parameter ordering is rearranged
590 * to simplify usage from generated bytecodes.
591 *
592 * @since 1.0.0
593 */
594 public static void set(Object target, byte value, Field field) {
595 set(target, field, value);
596 }
597
598 /**
599 * Set the value of the given field in the given object.
600 * Same behavior as above methods, but parameter ordering is rearranged
601 * to simplify usage from generated bytecodes.
602 *
603 * @since 1.0.0
604 */
605 public static void set(Object target, char value, Field field) {
606 set(target, field, value);
607 }
608
609 /**
610 * Set the value of the given field in the given object.
611 * Same behavior as above methods, but parameter ordering is rearranged
612 * to simplify usage from generated bytecodes.
613 *
614 * @since 1.0.0
615 */
616 public static void set(Object target, double value, Field field) {
617 set(target, field, value);
618 }
619
620 /**
621 * Set the value of the given field in the given object.
622 * Same behavior as above methods, but parameter ordering is rearranged
623 * to simplify usage from generated bytecodes.
624 *
625 * @since 1.0.0
626 */
627 public static void set(Object target, float value, Field field) {
628 set(target, field, value);
629 }
630
631 /**
632 * Set the value of the given field in the given object.
633 * Same behavior as above methods, but parameter ordering is rearranged
634 * to simplify usage from generated bytecodes.
635 *
636 * @since 1.0.0
637 */
638 public static void set(Object target, int value, Field field) {
639 set(target, field, value);
640 }
641
642 /**
643 * Set the value of the given field in the given object.
644 * Same behavior as above methods, but parameter ordering is rearranged
645 * to simplify usage from generated bytecodes.
646 *
647 * @since 1.0.0
648 */
649 public static void set(Object target, long value, Field field) {
650 set(target, field, value);
651 }
652
653 /**
654 * Set the value of the given field in the given object.
655 * Same behavior as above methods, but parameter ordering is rearranged
656 * to simplify usage from generated bytecodes.
657 *
658 * @since 1.0.0
659 */
660 public static void set(Object target, short value, Field field) {
661 set(target, field, value);
662 }
663
664 /**
665 * Invoke the given setter on the given object.
666 */
667 public static void set(Object target, Method setter, Object value) {
668 if (target == null || setter == null)
669 return;
670 makeAccessible(setter, setter.getModifiers());
671 try {
672 setter.invoke(target, new Object[] { value });
673 } catch (Throwable t) {
674 throw wrapReflectionException(t);
675 }
676 }
677
678 /**
679 * Invoke the given setter on the given object.
680 */
681 public static void set(Object target, Method setter, boolean value) {
682 set(target, setter, (value) ? Boolean.TRUE : Boolean.FALSE);
683 }
684
685 /**
686 * Invoke the given setter on the given object.
687 */
688 public static void set(Object target, Method setter, byte value) {
689 set(target, setter, new Byte(value));
690 }
691
692 /**
693 * Invoke the given setter on the given object.
694 */
695 public static void set(Object target, Method setter, char value) {
696 set(target, setter, new Character(value));
697 }
698
699 /**
700 * Invoke the given setter on the given object.
701 */
702 public static void set(Object target, Method setter, double value) {
703 set(target, setter, new Double(value));
704 }
705
706 /**
707 * Invoke the given setter on the given object.
708 */
709 public static void set(Object target, Method setter, float value) {
710 set(target, setter, new Float(value));
711 }
712
713 /**
714 * Invoke the given setter on the given object.
715 */
716 public static void set(Object target, Method setter, int value) {
717 set(target, setter, new Integer(value));
718 }
719
720 /**
721 * Invoke the given setter on the given object.
722 */
723 public static void set(Object target, Method setter, long value) {
724 set(target, setter, new Long(value));
725 }
726
727 /**
728 * Invoke the given setter on the given object.
729 */
730 public static void set(Object target, Method setter, short value) {
731 set(target, setter, new Short(value));
732 }
733 }