1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package net.sf.morph.util;
17
18 import java.lang.reflect.Method;
19 import java.lang.reflect.Modifier;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import net.sf.composite.util.DelegatingInvocationHandler;
24 import net.sf.composite.util.ObjectPair;
25
26 /**
27 * DelegatingInvocationHandler that uses reflection to invoke non-public methods
28 * that match invocation signatures.
29 */
30 public class AnyAccessDelegatingInvocationHandler extends DelegatingInvocationHandler {
31 private static class MethodDescription {
32 private final String name;
33 private final Class[] parameterTypes;
34 private int hashCode;
35 private MethodDescription(Method m) {
36 this.name = m.getName();
37 this.parameterTypes = m.getParameterTypes();
38 hashCode = name.hashCode();
39 for (int i = 0; i < parameterTypes.length; i++) {
40 hashCode += parameterTypes[i].hashCode() * i;
41 }
42 }
43
44 public boolean equals(Object obj) {
45 if (this == obj) {
46 return true;
47 }
48 if (!(obj instanceof MethodDescription)) {
49 return false;
50 }
51 return ((MethodDescription) obj).hashCode == this.hashCode;
52 }
53
54 public int hashCode() {
55 return hashCode;
56 }
57 }
58
59 private static final Map METHOD_MAP = new HashMap();
60
61 /**
62 * Construct a new AnyAccessDelegatingInvocationHandler.
63 * @param delegate
64 */
65 public AnyAccessDelegatingInvocationHandler(Object delegate) {
66 super(delegate);
67 }
68
69 protected Method getDelegateMethod(Object delegate, Method method, Object[] args) throws Exception {
70 try {
71 return super.getDelegateMethod(delegate, method, args);
72 } catch (Exception e) {
73 MethodDescription methodDescription = new MethodDescription(method);
74 ObjectPair key = new ObjectPair(delegate.getClass(), methodDescription);
75 Method result;
76 synchronized (METHOD_MAP) {
77
78 if (METHOD_MAP.containsKey(key)) {
79 result = (Method) METHOD_MAP.get(key);
80 }
81 result = getNonPublicMethod(delegate, method);
82 METHOD_MAP.put(key, result);
83 }
84 if (result == null) {
85 throw new NoSuchMethodException(method.toString());
86 }
87 if (!result.isAccessible()) {
88 result.setAccessible(true);
89 }
90 return result;
91 }
92 }
93
94 private Method getNonPublicMethod(Object delegate, Method method) {
95 for (Class current = delegate.getClass(); current != null; current = current.getSuperclass()) {
96 Method[] m = current.getDeclaredMethods();
97 for (int i = 0; i < m.length; i++) {
98 if (!Modifier.isPublic(m[i].getModifiers())
99 && m[i].getName().equals(method.getName())
100 && equals(m[i].getParameterTypes(), method.getParameterTypes())) {
101 return m[i];
102 }
103 }
104 }
105 return null;
106 }
107
108 private static boolean equals(Class[] c1, Class[] c2) {
109 if (c1.length != c2.length) {
110 return false;
111 }
112 for (int i = 0; i < c1.length; i++) {
113 if (c1[i] != c2[i]) {
114 return false;
115 }
116 }
117 return true;
118 }
119 }