我尝试重新转换班级时无法重新定义班级 [英] Failed to redefine class When I try to retransform class

查看:501
本文介绍了我尝试重新转换班级时无法重新定义班级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I was trying to modify class dynamically, such as call sleep() before a line. I attached agent to a jvm during runtime using Attach method. Then I got target class from jvm, and modified it(Add a line to call sleep()). And I got redine class error. I am using JDK1.6. I am using ASM core API to modify class. 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)

ASM代码是否有问题?实际上,我的ASM代码完成了它的工作(添加一行以调用sleep()).当前的jvm不支持retransform类吗?似乎无法执行retransformClasses(). retransformClasses()是否不支持ASM操作(将线添加到调用sleep()的方法中)?有任何想法吗?

Is there something wrong with ASM code? Actually my ASM code finished its job(to Add a line to call sleep()). Does current jvm not support retransform class? It seems failed to execute retransformClasses(). Does retransformClasses() not support the ASM operation(to add a line into a method to call sleep())? Any ideas? thx

我要修改的类:

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除了存储该类的字节码外,还具有一些表,用于跟踪每个类中字段的类型和方法的签名.

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.

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

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.

如果您将代理jar放在命令行中,则可以在首次加载类之前执行操作.如果在存储签名信息之前添加方法,那应该很好.

If you instead put your agent jar onto the command line, you can do things before the class is loaded for the first time. 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.

这篇关于我尝试重新转换班级时无法重新定义班级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆