Javassist:如何解决重复的类异常?

问题描述 投票:0回答:1

使用

Javassist
我正在尝试将一行代码插入方法的主体中。这是对
intellij-IDE
内标签文本颜色的简单修改。尝试这样做时出现以下错误:

引起:java.lang.LinkageError:加载器 com.intellij.util.lang.UrlClassLoader @d2cc05a 尝试为 com.intellij.ui.components.labels.LinkLabel 重复类定义。 (com.intellij.ui.components.labels.LinkLabel 位于加载器 com.intellij.util.lang.UrlClassLoader @d2cc05a、父加载器“platform”的未命名模块中)

这意味着我试图修改的类已经被 Java 类加载器加载了(至少我喜欢这样认为..)。 代码示例如下:

private static void test() {
        try {
            ClassPool cp = ClassPool.getDefault();
            CtClass cc = cp.get("com.intellij.ui.components.labels.LinkLabel");
            CtMethod cm = cc.getDeclaredMethod("getTextColor");
            cm.insertBefore("System.out.println(\"helloworld\");");

            cc.toClass(); // <--- the problem
        } catch (final Throwable e) {
            e.printStackTrace();
        }
    }

作为参考,这里是访问的类:intellij 链接


Rafael Winterhalter 几年前评论过类似的问题(link)。不幸的是,我对

Javassist
的了解限制了我找到合适的解决方案。

关于如何解决这个问题有什么想法吗?


更新:可以在这里找到一个最小的、可重复的示例:github链接

java intellij-idea bytecode javassist linkageerror
1个回答
0
投票

我知道这是一个老问题,但当你搜索“重复的类定义javassist”时,它是谷歌上的最高结果,所以我不妨分享可能的解决方案。

您遇到的问题是因为该类已经加载到类池中。在类加载到类池之前,您必须修改/重新定义类。

在您的特定问题中,您正在尝试重新定义

com.intellij.ui.components.labels.LinkLabel
。这个class有一个名为
ourVisitedLinks
的静态字段。此静态字段将强制在第一次提及
LinkLabel
类时加载
LinkLabel
类。

当您调用

cc.toClass()
时,您实际上是在引用
LinkLabel
类,从而将该类加载到类池中,因为静态字段
ourVisitedLinks
已初始化。因此,在加载该类的修改版本之前,
LinkLabel
类会隐式加载到类池中。

我承认我不明白 javassist 内部发生的一切。我只知道由于静态字段被初始化,

cc.toClass()
会抢先将类加载到类池中。

您必须致电

cc.toClass(SomeNeighbor.class)
SomeNeighbor.class
是我为示例虚构的一个类。它必须是与您尝试重新定义的类位于同一包中的类。

LinkLabel
类具有以下邻居,它们共享相同的包
com.intellij.ui.components.labels

  • 行动链接
  • 粗体标签
  • 下拉链接
  • 链接监听器
  • SwingActionLink

您可以选择这 5 个类中的任何一个作为邻居,只要该类不具有

LinkLabel
的任何直接或传递静态依赖项。

这是问题中示例的更正代码。遗憾的是,问题中共享的 github 链接无法再访问,因此我无法提供完美的可执行示例。

private static void test() {
   try {
        ClassPool cp = ClassPool.getDefault();
        CtClass cc = cp.get("com.intellij.ui.components.labels.LinkLabel");
        CtMethod cm = cc.getDeclaredMethod("getTextColor");
        cm.insertBefore("System.out.println(\"helloworld\");");

        cc.toClass(BoldLabel.class); // <--- the correction
    } catch (final Throwable e) {
            e.printStackTrace();
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.