11

以下のように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() を呼び出し、さらに 1 つ深いレベルで、エラー スタック トレースに表示される ExtendedArrayList.sort() が呼び出されることが観察されました。JDiagram の「ExtendedArrayList」は ArrayList を拡張し、次の定義を持つ「sort()」という名前のメソッドを含みます。

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

Google で、JRE 8 が List.sort() を導入し、Collections.sort() 呼び出しをコレクション (私の場合は ExtendedArrayList) の並べ替えメソッドに委任することがわかりました。そのため、ライブラリ ExtendedArrayList.sort() がオーバーライドになりました。そして、スタックオーバーフローを引き起こす無限再帰を作成します。小さなコードでもこの問題を再現できました。

また

  • JDiagram オブジェクトを作成する元のクラスは、製品の他のコンポーネントによって実行時にロードされます。プログラムのロードをほとんど制御できません。
  • JDiagram の最新バージョンでは、sort() メソッドを sortJ7() メソッドに置き換えることでこの問題が修正されていることがわかりました。ただし、現時点ではライブラリをアップグレードできません。JDiagram はライセンスされた API です。
  • ExtendedArrayList は JDiagram によって内部的にインスタンス化されているため、コードから変更することはできません。

これまでに機能しなかった次のソリューションを試しました

  • Java プロキシ: 私たちのコードは ExtendedArrayList を直接呼び出さず、'Diagram' にはインターフェイスがないためです。
  • Spring AOP: Spring を使用しておらず、プログラムは他のコンポーネントによって実行時に読み込まれます。
  • AspectJ: 今では、これは明らかに解決策でした。ただし、実行時にプログラムを織り込むことができないため、これも機能しませんでした。誰かがそれを機能させることができるかどうかはわかりません。

補足が必要な点があれば教えてください。どんな助けでも大歓迎です。ありがとう。

更新 これまでのところ、javassist が最良のアプローチですが、JDiagram の難読化により、ソリューションが正しく機能しません。私たちは、リリース日を頭の中で考えると、修正することは不可能 (と言わざるを得ない) であると想定しています。ライブラリをアップグレードするプロセスを開始しました。その間、routeAllLinks() メソッドによって提供されていたアプリケーションから小さな機能を削除しました.. :-( 皆さんの助けに感謝します. この問題は本当に興味深く、挑戦的であることがわかったので、この問題に関する研究を続けます.. 「解決できたら投稿を更新します..そして、研究を続けているので、@gontard の javassist アプローチに対して報奨金を与えます.ありがとう.

4

3 に答える 3

6

基本的な例で問題を再現しました:

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
    }
}

javassistjava.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

于 2015-03-18T14:48:20.517 に答える
2

ライブラリを逆コンパイルして、自分で問題を修正することを考えてください。この修正済みパッケージを回避策として使用できます。

別の方法として、固定バージョンのクラスをコードに配置することもできます。もちろん、ライブラリと同じクラス名のような同じパッケージ:

com.mindfusion.common.ExtendedArrayList

最初にライブラリ内の障害のあるクラスを検索するのではなく、クラスをロードするようにクラスローダーを構成する必要があるかもしれません。「親が最初」のようなオプションや、ライブラリを呼び出す前にコードからクラスにアクセスするだけで、取引が成立する可能性があります。

于 2015-03-24T12:23:45.110 に答える