我正在使用如下所示的 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/