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

gzszwxb4  于 2023-08-01  发布在  Java
关注(0)|答案(1)|浏览(186)

使用Javassist,我试图将一行代码插入到方法体中。这是对intellij-IDE中标签文本颜色的简单修改。我在尝试这样做时得到以下错误:

  • 原因:java.lang.LinkageError:loader 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 link
Rafael Winterhalter在几年前评论了一个类似的问题(链接)。不幸的是,我对Javassist的了解限制了我找到合适的解决方案。
有什么办法解决这个问题吗?

**更新:**一个最小的,可重复的例子可以在这里找到:github link

iswrvxsc

iswrvxsc1#

我知道这是一个老问题了,但是当你在google上搜索“重复的类定义javassist”时,它是最常见的结果,所以我不妨分享一下可能的解决方案。
您遇到的问题是因为类已经加载到类池中。在将类加载到类池之前,必须修改/重新定义类。
在您的特定问题中,您试图重新定义com.intellij.ui.components.labels.LinkLabel。这个类有一个名为ourVisitedLinks的静态字段。这个静态字段将强制在第一次提到LinkLabel类时加载LinkLabel类。
当调用cc.toClass()时,实际上是引用LinkLabel类,并将该类加载到类池中,因为静态字段ourVisitedLinks已初始化。因此,LinkLabel类在加载类的修改版本之前被隐式加载到类池中。
我承认我并不理解javassist中发生的一切。我只知道cc.toClass()会因为静态字段被初始化而抢先将类加载到类池中。
您将不得不改为调用cc.toClass(SomeNeighbor.class)SomeNeighbor.class是我为示例创建的一个虚构类。它只需要是一个类,是在同一个包中的类,你试图重新定义。
LinkLabel类有以下neighbors,它们共享同一个包com.intellij.ui.components.labels

  • ActionLink
  • BoldLabel
  • DropDownLink
  • LinkListener
  • 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();
    }
}

字符串

相关问题