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