• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package test3;
2 
3 import javassist.*;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Field;
6 
7 /* Test code
8  */
9 class EnhanceTest {
EnhanceTest()10     public EnhanceTest() { super(); }
foo(String s)11     public void foo(String s) { System.out.println(s); }
12 }
13 
14 @SuppressWarnings({"rawtypes","unchecked","unused"})
15 public class Enhancer {
16     private ClassPool pool;
17     private CtClass superClass;
18     private CtClass thisClass;
19     private Class thisJavaClass;
20     private Interceptor interceptor;
21     private int unique;
22 
23     private static final String INTERCEPTOR = "interceptor";
24 
25     /* Test method
26      */
main(String[] args)27     public static void main(String[] args) throws Exception {
28         Enhancer e = new Enhancer(test3.EnhanceTest.class);
29         e.overrideAll();
30         e.setCallback(new Interceptor() {
31                 public Object invoke(Object self, Method m, Object[] args)
32                     throws Exception
33                 {
34                     System.out.println("intercept: " + m);
35                     return m.invoke(self, args);
36                 }
37             });
38         Class c = e.createClass();
39         EnhanceTest obj = (EnhanceTest)c.getConstructor().newInstance();
40         obj.foo("test");
41     }
42 
43     public static interface Interceptor {
invoke(Object self, Method m, Object[] args)44         Object invoke(Object self, Method m, Object[] args) throws Exception;
45     }
46 
Enhancer(Class clazz)47     public Enhancer(Class clazz)
48         throws CannotCompileException, NotFoundException
49     {
50         this(makeClassPool(clazz).get(clazz.getName()));
51     }
52 
makeClassPool(Class clazz)53     private static ClassPool makeClassPool(Class clazz) {
54         ClassPool cp = new ClassPool();
55         cp.appendSystemPath();
56         cp.insertClassPath(new ClassClassPath(clazz));
57         return cp;
58     }
59 
Enhancer(CtClass superClass)60     public Enhancer(CtClass superClass)
61         throws CannotCompileException, NotFoundException
62     {
63         this.pool = superClass.getClassPool();
64         this.superClass = superClass;
65         String name = superClass.getName() + "_proxy";
66         thisClass = pool.makeClass(name);
67         thisClass.setSuperclass(superClass);
68         String src =
69             "public static " + this.getClass().getName()
70           + ".Interceptor " + INTERCEPTOR + ";";
71 
72         thisClass.addField(CtField.make(src, thisClass));
73         this.thisJavaClass = null;
74         unique = 0;
75     }
76 
overrideAll()77     public void overrideAll()
78         throws CannotCompileException, NotFoundException
79     {
80         CtMethod[] methods = superClass.getMethods();
81         String delegatorNamePrefix = thisClass.makeUniqueName("d");
82         for (int i = 0; i < methods.length; i++) {
83             CtMethod m = methods[i];
84             int mod = m.getModifiers();
85             if (!Modifier.isFinal(mod) && !Modifier.isAbstract(mod)
86                 && !Modifier.isStatic(mod))
87                 override(m, delegatorNamePrefix + i);
88         }
89     }
90 
override(CtMethod m, String delegatorName)91     public void override(CtMethod m, String delegatorName)
92         throws CannotCompileException, NotFoundException
93     {
94         String fieldName = "m" + unique++;
95         thisClass.addField(
96             CtField.make("private java.lang.reflect.Method "
97                          + fieldName + ";", thisClass));
98         CtMethod delegator = CtNewMethod.delegator(m, thisClass);
99         delegator.setModifiers(Modifier.clear(delegator.getModifiers(),
100                                               Modifier.NATIVE));
101         delegator.setName(delegatorName);
102         thisClass.addMethod(delegator);
103         thisClass.addMethod(makeMethod(m, fieldName, delegatorName));
104     }
105 
makeMethod(CtMethod m, String fieldName, String delegatorName)106     private CtMethod makeMethod(CtMethod m, String fieldName,
107                                 String delegatorName)
108         throws CannotCompileException, NotFoundException
109     {
110         String factory = this.getClass().getName() + ".findMethod(this, \"" +
111             delegatorName + "\");";
112         String body
113             = "{ if (" + fieldName + " == null) " +
114                    fieldName + " = " + factory +
115                  "return ($r)" + INTERCEPTOR + ".invoke(this, " + fieldName +
116             				                ", $args); }";
117         CtMethod m2 = CtNewMethod.make(m.getReturnType(),
118                                        m.getName(),
119                                        m.getParameterTypes(),
120                                        m.getExceptionTypes(),
121                                        body, thisClass);
122         m2.setModifiers(Modifier.clear(m.getModifiers(),
123                                        Modifier.NATIVE));
124         return m2;
125     }
126 
127     /* A runtime support routine called by an enhanced object.
128      */
findMethod(Object self, String name)129     public static Method findMethod(Object self, String name) {
130         Method[] methods = self.getClass().getMethods();
131         int n = methods.length;
132         for (int i = 0; i < n; i++)
133             if (methods[i].getName().equals(name))
134                 return methods[i];
135 
136         throw new RuntimeException("not found " + name
137                                    + " in " + self.getClass());
138     }
139 
createClass()140     public Class createClass() {
141         if (thisJavaClass == null)
142             try {
143                 thisClass.debugWriteFile();
144                 thisJavaClass = thisClass.toClass();
145                 setInterceptor();
146             }
147             catch (CannotCompileException e) {
148                 throw new RuntimeException(e);
149             }
150 
151         return thisJavaClass;
152     }
153 
writeFile(CtClass cc)154     private static void writeFile(CtClass cc) {
155         try {
156             cc.stopPruning(true);
157             cc.writeFile();
158             cc.defrost();
159             cc.stopPruning(false);
160         }
161         catch (Exception e) {
162             throw new RuntimeException(e);
163         }
164     }
165 
setCallback(Interceptor mi)166     public void setCallback(Interceptor mi) {
167         interceptor = mi;
168         setInterceptor();
169     }
170 
setInterceptor()171     private void setInterceptor() {
172         if (thisJavaClass != null && interceptor != null)
173             try {
174                 Field f = thisJavaClass.getField(INTERCEPTOR);
175                 f.set(null, interceptor);
176             }
177             catch (Exception e) {
178                 throw new RuntimeException(e);
179             }
180     }
181 }
182