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

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

问题描述

我试图动态修改类,例如在一行之前调用 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天全站免登陆