无法重新定义类当我尝试重新转换类时

我试图动态修改类,例如在行之前调用sleep()。 我在运行时使用Attach方法Attach代理程序Attach到jvm。 然后我从jvm获得了目标类,并对其进行了修改(添加一行来调用sleep() )。 我得到了redine类错误。 我使用的是JDK1.6。 我正在使用ASM核心API来修改类。 错误:

 Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields) at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method) at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:124) 

ASM代码有问题吗? 实际上我的ASM代码完成了它的工作(添加一行来调用sleep() )。 当前的jvm不支持转换类吗? 似乎无法执行retransformClasses()retransformClasses()不支持ASM操作(在方法中添加一行来调用sleep() )? 有任何想法吗? 谢谢

编辑:我要修改的类:

 import java.util.concurrent.TimeUnit; public class Person { public String name = "abc"; public String address = "xxxxx" ; public void setName(String name) { this.name = name; } public String getName() { return name; } public void sayHello() throws InterruptedException { System.out.println("aaaaaaaaaa"); System.out.println("Hello World!"); TimeUnit.SECONDS.sleep(120); System.out.println("dd"); } public void sayHello2() { System.out.println("aaaaaaaaaa1"); System.out.println("Hello World!2"); } public static void main (String args[]) { try { Person p = new Person(); p.sayHello(); // linenumber #9. A line to call Sleep() should be added before #here. p.sayHello2(); } catch (InterruptedException e) { e.printStackTrace(); } } } 

我的ASM代码:

 public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) { Label la=new Label(); mv.visitLabel(la); int linenumber=la.getOffset(); if(linenumber==9) { mv.visitFieldInsn(Opcodes.GETSTATIC, "java/util/concurrent/TimeUnit", "SECONDS", "Ljava/util/concurrent/TimeUnit;"); mv.visitLdcInsn(new Long("5")); mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/concurrent/TimeUnit", "sleep", "(J)V"); super.visitMethodInsn(arg0, arg1, arg2, arg3); } } 

还没看你的代码,我想我可以提出一些建议。 首次加载类时,除了存储类的字节代码之外,JVM还具有表,用于跟踪每个类中的字段类型和方法的签名。

您看到的错误表明该类已加载,此签名信息已存储,然后您尝试在此之后添加该方法。

如果您将代理jar放在命令行上,则可以在第一次加载类之前执行操作。 如果您在签名信息被存储之前添加您的方法,您应该是好的。

如果必须在已启动进程后连接代理,则可能可以转换类,但您可能只能在不更改字段集,类型或方法或其签名的情况下对其进行转换。 换句话说,您可以更改字节代码,但不必使先前存储的元信息无效。