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