You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Enhancer.java 5.9KB

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