gpt4 book ai didi

java - 使用 javassist 更改类(java 反射)

转载 作者:塔克拉玛干 更新时间:2023-11-03 04:15:02 25 4
gpt4 key购买 nike

我有以下代码。我想更改 hello 类的 say 方法。我使用javassist。我有以下错误。

public class TestJavasisit {
/**
* @param args the command line arguments
* @throws java.lang.Exception
*/
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
// version original
Hello h1 = new Hello();
h1.say();
CtClass cc = pool.get("testjavasisit.Hello");
cc.defrost();
CtMethod m = cc.getDeclaredMethod("say");
m.insertBefore("{ System.out.println(\"Hello.say():\"); }");
cc.writeFile(".");
cc.toClass();
// version modifie
Hello h2 = new Hello();
h2.say();
}

}

问候类:

public class Hello {

public void say() {
System.out.println("Hello");
}
}

错误信息:

run:
Hello
Exception in thread "main" javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "testjavasisit/Hello"

最佳答案

代码:

package testjavasisit;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class TestJavasisit {
/**
* @param args
* the command line arguments
* @throws java.lang.Exception
*/
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();

// version original
Hello h1 = new Hello(); // remove this line
h1.say(); // remove this line

CtClass cc = pool.get("testjavasisit.Hello");
cc.defrost();
CtMethod m = cc.getDeclaredMethod("say");
m.insertBefore("{ System.out.println(\"Hello.say():\"); }");
cc.writeFile(".");
// This throws a java.lang.LinkageError ... attempted duplicate class definition for name: ...
cc.toClass();
// version modifie
Hello h2 = new Hello();
h2.say();
}

}

调试与解决:

如果你去掉下面两行,那么它就会运行成功。

   // Hello h1 = new Hello();
// h1.say();

输出:

Hello.say():

Hello

根本原因分析:

当您第一次使用 Hello h1 = new Hello(); 时,类加载器会加载 Hello 类。

之后,当您再次尝试使用 cc.toClass(); 加载 Hello 类时,出现此错误。

发生原因:

Rafael Winterhalter在此link讲了原因和一些解决办法作为

cc.toClass() takes a loaded class[Hello] and redefines this very same class without changing its name. After this redefinition, you attempt to load the altered class one more time. This is however not possible in Java where any ClassLoader can only load a class of a given name one single time.

To overcome your problem, you have different choices:

  1. Create a subclass of the argument class (or use interfaces) which uses a random name. The subclass is then type compatible to your argument class but is never loaded.
  2. Use the Instrumentation API to redefine your loaded class at runtime.
  3. Make sure that the input class and the output class are loaded with different ClassLoaders. (not recommended)

此处描述了相同类型的问题:

在tomcat中,他们已经解决了这个问题。

  1. https://github.com/brettwooldridge/HikariCP/issues/217
  2. http://forum.spring.io/forum/spring-projects/container/58952-use-javassist-modify-class-error-when-in-lib

关于java - 使用 javassist 更改类(java 反射),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40105981/

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