JavaJavassist:copy方法和调试信息?
在从公共祖先类派生的大量类中,我有一个方法something()
,我想修改它的行为来度量执行时间。
我在公共祖先类中定义了另外两个方法
// in the common ancestor class:
// this method is defined in all derived classes
public void something() {
System.out.println("something{");
System.out.println("something}");
}
// the body of this method will replace the body of something()
public void measuredSomething() {
System.out.println("measuredSomething{");
roomForSomething();
System.out.println("measuredSomething}");
}
// the body of this method will be replaced by the body of something()
public void roomForSomething() {
// this code will be replaced with something else
System.out.println("roomForSomething{");
System.out.println("roomForSomething}");
}
我用Javassist进行替换:
// someClass is known
String superClassName = someClass.getName();
String className = superClassName + "__proxy";
CtClass ctSuperClass = ClassPool.getDefault().get(superClassName);
CtClass ctClass = ClassPool.getDefault().makeClass(className);
ctClass.setSuperclass(ctSuperClass);
// roomForSomething := something
CtMethod methodSomething = ctSuperClass.getMethod("something", "()V");
CtMethod methodSomething2 = CtNewMethod.copy(methodSomething, "roomForSomething", ctClass, null);
ctClass.addMethod(methodSomething2);
// something := measuredSomething
// (and measuredSomething() will call roomForSomething())
CtMethod methodMeasuredSomething = ctSuperClass.getMethod("measuredSomething", "()V");
CtMethod methodMeasuredSomething2 = CtNewMethod.copy(methodMeasuredSomething, "something", ctClass, null);
ctClass.addMethod(methodMeasuredSomething2);
someClass = ctClass.toClass();
result = someClass.newInstance();
它是有效的。但调试器无法显示执行的代码
如何将调试信息与字节码一起复制,以便调试器显示执行的源代码
(修改方法代码时不可能,但在这种特殊情况下应该可以。)
((我确实建议将方法something()
分为两个方法,就像有Thread.run()
要重写,有Thread.start()
要调用一样。我被要求避免这样的更改。)
更新
下面的方法给出了更好的结果:调试器仅在从被调用函数返回时才在通过CtMethod.make()
生成的函数中停止;生成的函数在堆栈跟踪中可见;生成的函数的源不可用
// something := measuredSomething
CtMethod methodSomething = CtMethod.make("public void something() {super.measuredSomething();}", ctClass);
ctClass.addMethod(methodSomething);
// roomForSomething := something
CtMethod methodRoomForSomething = CtMethod.make("public void roomForSomething() {super.something();}", ctClass);
ctClass.addMethod(methodRoomForSomething);
如果能够显示生成函数的源代码,那就太好了
# 1 楼答案
我不认为您可以使用Javassist直接调试注入的代码,因为这个库只能修改字节码(因此实际上源代码没有更改)。这意味着您的调试器无法访问您注入的代码,因为它基本上不存在(这只是您表达字节码生成的一种图形方式)
顺便说一下,我也遇到了同样的问题,我的目标是调试roomForSomething方法。我的解决方案是:首先在类中声明要调试的方法(在您的例子中是roomForSomething()),并使其成为静态的
在您可以使用Javassist将对该静态方法的调用注入到修改后的方法中之后。即使在类中没有导入定义“roomForSomething”的类,也可以像我在示例中所做的那样指定类的完全限定名
使用此解决方案,您可以在“roomForSomething”代码中设置断点