method jdk interfaces functional example java arraylist collections java-8 default-method

java - jdk - La versión anterior de JDiagram arroja StackOverflowError con JRE 8 en ExtendedArrayList.sort



public default java (3)

Estoy usando JDiagram JAR como a continuación

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

Este código funciona bien cuando se ejecuta con JRE 7; sin embargo, cuando se ejecuta con JRE 8, se produce el siguiente error:

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)

Seguí el rastro de la pila al código decompilado de JDiagram. Se observó que routeAllLinks () llama a RouteLinks () en otro objeto (por ejemplo, el enrutador) y en un nivel más profundo se llama a ExtendedArrayList.sort () que aparece en la pila de errores. El "ExtendedArrayList" en JDiagram amplía ArrayList y contiene un método llamado "sort ()" que tiene la siguiente definición.

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

En Google descubrí que JRE 8 ha introducido List.sort () y delega las llamadas Collections.sort () al método de ordenamiento de colecciones (ExtendedArrayList en mi caso). Y así la biblioteca ExtendedArrayList.sort () se convirtió en una anulación. Y crea una recursión infinita que da como resultado stackoverflow. Podría reproducir este problema incluso con un pequeño fragmento de código también ahora.

también

  • Nuestra clase original, que crea el objeto JDiagram, está siendo cargada en tiempo de ejecución por algún otro componente de nuestro producto. Tenemos muy poco control sobre la carga de nuestro programa.
  • Hemos descubierto que la última versión de JDiagram ha solucionado este problema reemplazando sort () con el método sortJ7 (). Sin embargo, no podemos actualizar la biblioteca en este momento. JDiagram es una API con licencia.
  • ExtendedArrayList está siendo instanciado por JDiagram internamente, por lo que no podemos modificarlo desde nuestro código.

Hemos intentado seguir soluciones que hasta ahora no funcionaban

  • Proxy de Java: Porque nuestro código no llama a ExtendedArrayList directamente y también ''Diagram'' no tiene ninguna interfaz.
  • Spring AOP: no estamos utilizando la primavera y también nuestro programa está cargado en tiempo de ejecución por otro componente.
  • AspectJ: Por ahora, esta fue aparentemente una solución. Sin embargo, tampoco funcionó ya que no podemos tejer nuestro programa en tiempo de ejecución. No estoy seguro si alguien podría hacer que funcione.

Por favor, hágamelo saber si algún punto necesita elaboración. Cualquier ayuda es bienvenida. Gracias.

ACTUALIZACIÓN Hasta ahora, javassist es el mejor enfoque, sin embargo, la ofuscación de JDiagram impide que la solución funcione correctamente. Supusimos que es imposible (tengo que decirlo) arreglarlo teniendo en cuenta nuestra fecha de lanzamiento en nuestra cabeza. Hemos comenzado el proceso para actualizar la biblioteca. Y mientras tanto, eliminó una pequeña característica de nuestra aplicación que fue proporcionada por el método routeAllLinks () .. :-( gracias a todos por su ayuda. Voy a continuar mi investigación sobre este tema, ya que me pareció realmente intrigante y desafiante ... Actualizaré la publicación si pudiera resolverlo ... Y le daré una recompensa a @gontard por su enfoque javassist mientras continúo mi investigación con eso. Gracias.


He reproducido tu problema con un ejemplo básico:

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

Pude pasar por alto java.lang.Error al renombrar el método usando javassist :

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

No he intentado con su versión de JDiagram porque solo obtengo la última versión (compatible con Java 8) en su sitio web.


Piensa en descompilar la biblioteca y solucionar el problema tú mismo. Puede usar este paquete fijo como una solución alternativa.

Una alternativa sería colocar una versión fija de la clase en su código . El mismo paquete como en la biblioteca y el mismo nombre de clase, por supuesto:

com.mindfusion.common.ExtendedArrayList

Quizás tenga que configurar el cargador de clases para cargar su clase en lugar de buscar primero la clase defectuosa en la biblioteca. Las opciones como "padre primero" o simplemente acceder a la clase desde su código una vez antes de llamar a la biblioteca podrían hacer el trato.


Veo que usted no controla la carga de su programa. Realice los siguientes pasos:

  1. Incluya el jar (javassist) del programa que podría cambiar el nombre del método "sort" a cualquier otro nombre que podría evitar anular el método de clasificación

  2. Cargue la clase principal jar (javassist) por reflexión class.forName(""); al comienzo del método principal de su programa

  3. Llame al método jar (javassist) para realizar los cambios necesarios que necesita en los métodos

De esta forma, puede estar seguro de que cualquier jar (javassist) está cargado y listo para ser utilizado.