gpt4 book ai didi

java - 如何避免 'javassist.CannotCompileException: no method body'

转载 作者:行者123 更新时间:2023-12-03 00:10:10 32 4
gpt4 key购买 nike

我正在使用 Java 工具和 Javassist将 print 语句插入方法中。这大多数情况下都不会出现错误,但对于某些类方法(例如 java.util.TimeZone.getSystemTimeZoneID),我收到以下异常:

javassist.CannotCompileException: no method body
at javassist.CtBehavior.insertBefore(CtBehavior.java:695)
at javassist.CtBehavior.insertBefore(CtBehavior.java:685)

我的代码尝试通过检查CtBehaviour.isEmpty()来避免此问题,但这没有什么区别。关于如何避免这种情况有什么建议吗?

这是一个最小的例子:

public class ExceptionExample implements ClassFileTransformer {

private static final ClassPool pool = ClassPool.getDefault();

public static void premain(String agentArgument,
Instrumentation instrumentation) {
instrumentation.addTransformer(new ExceptionExample());
}

@Override
public byte[] transform(final ClassLoader loader, final String className,
final Class<?> classBeingRedefined,
final ProtectionDomain protectionDomain, final byte[] classfileBuffer)
throws IllegalClassFormatException {

String dottedClassName = className.replace('/', '.');

if (dottedClassName.startsWith("java.lang")
|| dottedClassName.startsWith("java.util")) {

try {
System.out.println("Instrumenting: " + dottedClassName);
return adjustClass(dottedClassName, classBeingRedefined,
classfileBuffer);
} catch (Exception e) {
e.printStackTrace();
}
}

return classfileBuffer;
}

private byte[] adjustClass(final String className,
final Class<?> classBeingRedefined, final byte[] classfileBuffer)
throws IOException, RuntimeException, CannotCompileException {

CtClass cl = null;

try {
cl = pool.makeClass(new java.io.ByteArrayInputStream(classfileBuffer));
if (!cl.isInterface()) {
CtBehavior[] methods = cl.getDeclaredBehaviors();
for (CtBehavior method : methods) {
if (!method.isEmpty()) {
try {
method
.insertBefore(String.format(
"System.out.println(\"CALLING: %s\");",
method.getLongName()));
} catch (Throwable t) {
System.out.println("Error instrumenting " + className + "."
+ method.getName());
t.printStackTrace();
}
}
}
return cl.toBytecode();
}
} finally {
if (cl != null) {
cl.detach();
}
}
return classfileBuffer;
}
}

这是我正在测试的一个小类:

public class Main {

public static void main(String[] args) throws Exception {
Calendar c = Calendar.getInstance();
System.out.println(c.get(Calendar.YEAR));
}
}

示例输出(缩写):

Instrumenting: java.util.Calendar
CALLING: java.util.Calendar.<clinit>()
CALLING: java.util.Calendar.getInstance()
Instrumenting: java.util.TimeZone
Error instrumenting java.util.TimeZone.getSystemTimeZoneID
javassist.CannotCompileException: no method body
at javassist.CtBehavior.insertBefore(CtBehavior.java:695)
at javassist.CtBehavior.insertBefore(CtBehavior.java:685)
at com.cryptomathic.test.instrument.ExceptionExample.adjustClass(ExceptionExample.java:56)
at com.cryptomathic.test.instrument.ExceptionExample.transform(ExceptionExample.java:34)
at sun.instrument.TransformerManager.transform(Unknown Source)
at sun.instrument.InstrumentationImpl.transform(Unknown Source)
at java.util.Calendar.getInstance(Unknown Source)
at test.Main.main(Main.java:8)
Error instrumenting java.util.TimeZone.getSystemGMTOffsetID
javassist.CannotCompileException: no method body
at javassist.CtBehavior.insertBefore(CtBehavior.java:695)
at javassist.CtBehavior.insertBefore(CtBehavior.java:685)
at com.cryptomathic.test.instrument.ExceptionExample.adjustClass(ExceptionExample.java:56)
at com.cryptomathic.test.instrument.ExceptionExample.transform(ExceptionExample.java:34)
at sun.instrument.TransformerManager.transform(Unknown Source)
at sun.instrument.InstrumentationImpl.transform(Unknown Source)
at java.util.Calendar.getInstance(Unknown Source)
at test.Main.main(Main.java:8)
CALLING: java.util.TimeZone.<clinit>()
CALLING: java.util.TimeZone.getDefaultRef()
CALLING: java.util.TimeZone.getDefaultInAppContext()
CALLING: java.util.TimeZone.setDefaultZone()
CALLING: java.util.TimeZone.getTimeZone(java.lang.String,boolean)
CALLING: java.util.TimeZone.setID(java.lang.String)
...

最佳答案

您需要首先检查它是否是 native 方法,因为 native 方法不支持这些方法(insertBefore()、insertAfter()..)。我写了一个小方法来检测 CtMethod 是否是原生的:

public static boolean isNative(CtMethod method) {
return Modifier.isNative(method.getModifiers());
}

我已经测试过它,它有效并解决了您的问题。

注意:无法检测 native 方法,因为它们没有字节码。但是,如果支持 native 方法前缀 ( Transformer.isNativeMethodPrefixSupported() ),那么您可以使用 Transformer.setNativeMethodPrefix() 将 native 方法调用包装在非 native 调用中,然后可以对其进行检测。

关于java - 如何避免 'javassist.CannotCompileException: no method body',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22992546/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com