我正在使用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(),并在另一个层次上调用了出现在错误堆栈跟踪中的DeepExtendedArrayList.sort()。 JDiagram中的“ExtendedArrayList”扩展了ArrayList并包含一个名为“sort()”的方法,该方法具有以下定义。
  public void sort(Comparator<? super T> paramComparator)
  {
    Collections.sort(this, paramComparator);
  }

在Google上,我发现JRE 8引入了List.sort(),并将Collections.sort()调用委托(delegate)给collection的(在我的情况下为ExtendedArrayList)sort方法。因此,库ExtendedArrayList.sort()成为重写。并且它创建了无限递归,从而导致stackoverflow。即使现在只用一小段代码,我也可以重现此问题。


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

  • 我们已经尝试了以下解决方案,这些解决方案到目前为止还行不通
  • Java代理:因为我们的代码没有直接调用ExtendedArrayList
    而且“图”没有任何界面。
  • Spring AOP:我们是
    不使用 Spring ,我们的程序也被其他人加载运行时
    成分。
  • AspectJ:到目前为止,这显然是一个解决方案。然而,
    它也无法正常工作,因为我们无法在以下位置编织程序
    运行。不知道是否有人可以使它工作。

  • 请让我知道是否需要阐述。
    欢迎任何帮助。谢谢。

    更新
    到目前为止,javassist是最好的方法,但是JDiagram混淆阻止了该解决方案正常工作。考虑到我们的发布日期,我们有点假设无法(不得不说)修复该问题。我们已经开始升级库的过程。同时,从我们的应用程序中删除了一个由routeAllLinks()方法提供的小功能。
    感谢大家的帮助。我将继续对这个问题进行研究,因为我发现它确实很有趣并且具有挑战性。.如果可以解决,我将更新该帖子。我继续进行研究。谢谢。

    最佳答案

    我用一个基本的例子重现了您的问题:

    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的)版本。

    10-06 14:27