01: /*
02: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
03: * notice. All rights reserved.
04: */
05: package com.tc.util;
06:
07: import com.tc.asm.Type;
08:
09: import java.lang.reflect.InvocationHandler;
10: import java.lang.reflect.Method;
11: import java.lang.reflect.Proxy;
12: import java.util.HashMap;
13: import java.util.Map;
14:
15: /**
16: * Creates a proxy to allows a class containing the correct set of method signatures to stand in for an interface (w/o
17: * actually implementing it)
18: *
19: * NOTE: even if createProxyIfPossible() returns a proxy, it doesn't mean you want get ClassCastExceptions on the
20: * argument and/or return types -- The only checking that is done is on class names (ignoring loaders completely)
21: *
22: * NOTE (2): Since reflection is used, this probably isn't the fastest thing in town.
23: */
24: public class ReflectiveProxy {
25:
26: private ReflectiveProxy() {
27: //
28: }
29:
30: // TODO: one should really be able to pass an array of interfaces to this method
31: public static Object createProxyIfPossible(Class iface,
32: Object candidate) {
33: if (iface == null || !iface.isInterface()) {
34: throw new IllegalArgumentException(
35: "invalid class to proxy: " + iface);
36: }
37:
38: Map ifaceMethods = getMethods(iface);
39: Map instanceMethods = getMethods(candidate.getClass());
40:
41: if (!instanceMethods.keySet()
42: .containsAll(ifaceMethods.keySet())) {
43: return null;
44: }
45:
46: // all methods present
47: return Proxy.newProxyInstance(iface.getClassLoader(),
48: new Class[] { iface }, new Handler(candidate,
49: instanceMethods));
50: }
51:
52: private static Map getMethods(Class c) {
53: Map rv = new HashMap();
54:
55: Method[] methods = c.getMethods();
56: for (int i = 0; i < methods.length; i++) {
57: Method m = methods[i];
58: String key = makeMethodKey(m);
59: Object prev = rv.put(key, m);
60: if (prev != null) {
61: throw new AssertionError("replaced mapping for " + key);
62: }
63: }
64:
65: return rv;
66: }
67:
68: private static String makeMethodKey(Method m) {
69: return m.getName() + Type.getMethodDescriptor(m);
70: }
71:
72: public static class Handler implements InvocationHandler {
73: private final Object obj;
74: private final Map methods;
75:
76: public Handler(Object obj, Map methods) {
77: this .obj = obj;
78: this .methods = methods;
79: }
80:
81: public Object invoke(Object proxy, Method method, Object[] args)
82: throws Throwable {
83: String key = makeMethodKey(method);
84: Method targetMethod = (Method) methods.get(key);
85: if (targetMethod == null) {
86: throw new AssertionError("missing method for " + key);
87: }
88: targetMethod.setAccessible(true);
89: return targetMethod.invoke(obj, args);
90: }
91: }
92:
93: }
|