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.8KB

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