java - JDiagram 旧版本在 ExtendedArrayList.sort 中使用 JRE 8 抛出 StackOverflowError

标签 java arraylist collections java-8 default-method

我正在使用如下所示的 JDiagram JAR

Diagram myDigram = new Diagram();
    myDigram.routeAllLinks();

此代码在 JRE 7 上运行时运行良好,但在 JRE 8 上运行时,会抛出以下错误:

java.lang.StackOverflowError
    at java.util.Collections.sort(Unknown Source)
    at com.mindfusion.common.ExtendedArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at com.mindfusion.common.ExtendedArrayList.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at com.mindfusion.common.ExtendedArrayList.sort(Unknown Source)

我跟踪堆栈跟踪到 JDiagram 反编译代码。观察到 routeAllLinks() 在另一个对象(比如路由器)上调用 RouteLinks() 并且在更深的层次上调用出现在错误堆栈跟踪中的 ExtendedArrayList.sort() 。 JDiagram 中的“ExtendedArrayList”扩展了 ArrayList 并包含一个名为“sort()”的方法,其定义如下。

  public void sort(Comparator<? super T> paramComparator)
  {
    Collections.sort(this, paramComparator);
  }

在 Google 上,我发现 JRE 8 引入了 List.sort() 并将 Collections.sort() 调用委托(delegate)给集合的(在我的例子中是 ExtendedArrayList)排序方法。因此,库 ExtendedArrayList.sort() 成为了重写。它创建了一个无限递归,导致计算器溢出。我现在也可以用一小段代码重现这个问题。

还有

  • 我们创建 JDiagram 对象的原始类正在运行时由我们产品中的其他一些组件加载。我们几乎无法控制程序的加载。
  • 我们发现最新版本的 JDiagram 已通过将 sort() 替换为 sortJ7() 方法解决了此问题。但是,我们目前无法升级库。 JDiagram 是经过许可的 API。
  • ExtendedArrayList 正在由 JDiagram 内部实例化,因此我们不能从我们的代码中更改它。

我们已经尝试了以下目前没有奏效的解决方案

  • Java Proxy:因为我们的代码没有直接调用ExtendedArrayList 而且“图表”也没有任何界面。
  • Spring AOP:我们是 不使用 spring,而且我们的程序由其他人在运行时加载 零件。
  • AspectJ:到目前为止,这显然是一个解决方案。然而, 它也没有用,因为我们无法在 运行。不确定是否有人可以让它发挥作用。

如果有任何要点需要详细说明,请告诉我。 欢迎任何帮助。谢谢。

更新 到目前为止,javassist 是最好的方法,但是 JDiagram 混淆阻止了解决方案的正常工作。考虑到我们头脑中的发布日期,我们有点假设不可能(不得不说)修复。我们已经开始升级图书馆的过程。同时从我们的应用程序中删除了一个由 routeAllLinks() 方法提供的小功能。:-( 感谢大家的帮助。我将继续研究这个问题,因为我发现它真的很有趣和具有挑战性。如果我能解决它,我会更新帖子。我会奖励@gontard 的 javassist 方法,因为我'我继续研究它。谢谢。

最佳答案

我已经用一个基本示例重现了您的问题:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class ExtendedArrayList<E> extends ArrayList<E> {
    @Override
    public void sort(Comparator<? super E> c) {
        Collections.sort(this, c);
    }
}

import java.util.Arrays;

public class Main {
    public static void main(String[] args) throws Exception {
        ExtendedArrayList<String> arrayList = new ExtendedArrayList<String>();
        arrayList.addAll(Arrays.asList("z", "y", "x"));
        arrayList.sort(String::compareTo); // -> java.lang.StackOverflowError
    }
}

通过使用 javassist 重命名方法,我能够绕过 java.lang.StackOverflowError :

import java.util.Arrays;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

public class Main {
    public static void main(String[] args) throws Exception {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.get("ExtendedArrayList");
        CtClass[] sortParams = new CtClass[]{ pool.get("java.util.Comparator")};
        CtMethod sortMethod = ctClass.getDeclaredMethod("sort", sortParams);
        sortMethod.setName("sortV7"); // rename
        ctClass.toClass();

        ExtendedArrayList<String> arrayList = new ExtendedArrayList<String>();
        arrayList.addAll(Arrays.asList("z", "y", "x"));
        System.err.println(arrayList); // print [z, y, x]
        arrayList.sort(String::compareTo);
        System.err.println(arrayList); // print [x, y, z]
    }
}

我没有尝试使用您的 JDiagram 版本,因为我在他们的网站上只获得了最后一个(Java 8 兼容)版本。

关于java - JDiagram 旧版本在 ExtendedArrayList.sort 中使用 JRE 8 抛出 StackOverflowError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29069363/

相关文章:

java - 访问 Oracle SYS_REFCURSOR

java - 将 Hashmap 用于键的多个值,为什么?

c# - 我如何连接两个具有相同基类的不同列表<T>?

java - 如何将表格转换为 map 的 map

java - 搜索 arrayLists 的映射树

java - 访问 ArrayList<ArrayList<SomeObject>> 元素

java - Windows中执行计划任务时如何隐藏svchost.exe(dos提示符)

Java - 动态网格布局

java - Java/Groovy 中的电子表格解析器

javascript - 没有正则表达式的字母数字验证javascript