简体   繁体   English

我尝试重新转换班级时无法重新定义班级

[英]Failed to redefine class When I try to retransform class

I was trying to modify class dynamically, such as call sleep() before a line. 我试图动态地修改类,例如在一行之前调用sleep()。 I attached agent to a jvm during runtime using Attach method. 我在运行时使用Attach方法Attach代理附加到了jvm。 Then I got target class from jvm, and modified it(Add a line to call sleep() ). 然后我从jvm获取了目标类,并对其进行了修改(添加一行以调用sleep() )。 And I got redine class error. 而且我得到了redine类错误。 I am using JDK1.6. 我正在使用JDK1.6。 I am using ASM core API to modify class. 我正在使用ASM核心API来修改类。 The Error: 错误:

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)

Is there something wrong with ASM code? ASM代码有问题吗? Actually my ASM code finished its job(to Add a line to call sleep() ). 实际上,我的ASM代码完成了其工作(添加一行以调用sleep() )。 Does current jvm not support retransform class? 当前的jvm不支持retransform类吗? It seems failed to execute retransformClasses() . 似乎无法执行retransformClasses() Does retransformClasses() not support the ASM operation(to add a line into a method to call sleep() )? retransformClasses()是否不支持ASM操作(向方法中添加一行以调用sleep() )? Any ideas? 有任何想法吗? thx 谢谢

EDIT: The class which I want modify: 编辑:我要修改的类:

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();
        }
    }   
}

My ASM code: 我的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);

    }
}

Not looking at your code yet, I think I can suggest something. 还没看您的代码,我想我可以提出一些建议。 When a class is first loaded, in addition to storing the class's byte codes, the JVM also has tables where it keeps track of the types of fields and the signatures of methods in each class. 第一次加载类时,JVM除了存储该类的字节码外,还具有一些表,用于跟踪字段的类型和每个类中方法的签名。

The error you are seeing would suggest that the class was loaded, this signature information was stored and then you tried to add the method after that. 您看到的错误提示已加载该类,已存储此签名信息,然后尝试在此之后添加该方法。

If you instead put your agent jar onto the command line, you can do things before the class is loaded for the first time. 如果将代理jar放在命令行中,则可以在首次加载类之前执行操作。 If you add your method before the signature info is stored away, you should be good. 如果在存储签名信息之前添加方法,那应该很好。

If you have to connect the agent after the process is already launched, you may be able to transform the class but you may only be able to transform it without changing the set of fields, their types, or the methods, or their signatures. 如果必须在启动过程后连接该代理,则可以转换该类,但是只能转换其而无需更改字段集,其类型,方法或签名。 In other words, you may be able to change the byte codes but you have to not invalidate the previously-stored meta information. 换句话说,您可以更改字节码,但是不必使先前存储的元信息无效。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM