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