java - Excepciones de depuración en el hilo de cola AWT
scala debugging (3)
Estoy desarrollando una aplicación Swing con un componente que realiza una pintura personalizada. Cuando cometo un error en el código de pintura y se lanza una excepción, la situación es difícil de depurar. En lugar de ser atrapado por el depurador, aparece una ventana emergente con la información de excepción. Además, parece que el hilo se ha reiniciado y, como la excepción es un resultado del error de codificación, se muestra una y otra vez.
Cuando tengo la suerte de cambiar al depurador (lo cual es difícil, porque cada vez aparecen más ventanas emergentes a medida que la aplicación recibe solicitudes de pintura), la consola de depuración me muestra una información de excepción como:
SEVERE: excepción no detectada lanzada en Thread [AWT-EventQueue-0,6, principal]
.... sigue la pila
Mi aplicación está escrita en Scala y estoy usando IntelliJ IDEA 14. El depurador maneja bien mis excepciones de subprocesos principales no Uncaught exception
(tengo Uncaught exception
habilitada para Any exception
punto de interrupción de Any exception
habilitado en los puntos de interrupción de Any exception
Java Exception Breakpoints
), pero las excepciones en subprocesos AWT no .
He intentado instalar un controlador como se describe en este ¿Cómo puedo detectar cuándo se ha lanzado una excepción globalmente en Java? respuesta , pero mi controlador no parece activarse.
Me gustaría lograr lo siguiente (en orden de importancia):
- evitar el reinicio de la secuencia AWT en caso de excepción, o al menos evitar que se muestre la ventana emergente
- manejar excepciones no detectadas en el depurador en lugar de estar impresas en la consola
(Nota: si bien esta es la aplicación Scala, supongo que el comportamiento sería el mismo para Java, de ahí la etiqueta Java).
En Java
Su problema es que la excepción se está lanzando en otro hilo, el hilo de envío del evento. Un par de soluciones:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable e) {
logger.error("Uncaught exception in thread: " + t.getName, e);
}
});
En cualquier caso, debería en principio, pero su código de inicio de la interfaz de usuario en una
EventQueue.invokeLater();
o SwingUtilities.invokeLater () que llaman directamente esto.
En Scala
Su problema es que la excepción se está lanzando en otro hilo, el hilo de envío del evento. Un par de soluciones:
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
def uncaughtException(t: Thread, e: Throwable) {
logger.error("Uncaught exception in thread: " + t.getName, e)
}
})
En cualquier caso, debería en principio, pero su código de inicio de la interfaz de usuario en una
EventQueue.invokeLater()
De acuerdo con este enlace , tiene que manejar Exception
regular y Exception
EDT Exception
sin utilizar el viejo hack sun.awt.exception.handler
(que ya no funciona desde Java 7)
Aquí está su ExceptionHandler
public static class ExceptionHandler implements Thread.UncaughtExceptionHandler
{
public void uncaughtException(Thread thread, Throwable thrown)
{
// TODO handle your Exception here
}
}
Uso:
// Regular Exception
Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler());
// EDT Exception
SwingUtilities.invokeAndWait(new Runnable()
{
public void run()
{
// We are in the event dispatching thread
Thread.currentThread().setUncaughtExceptionHandler(new ExceptionHandler());
}
});
Parece que tu única solución podría ser cambiar a Eclipse. :-) Las otras soluciones requieren esfuerzo de codificación y detenerse en el manejador de excepciones no es lo mismo que detenerse en el lugar exacto donde se lanza la excepción.
Con el siguiente programa no tengo problemas para escuchar las instancias atrapadas / no detectadas de RuntimeException
en Eclipse.
package lambda;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class AWTExceptionTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("Test");
button.addActionListener(e -> { throw new RuntimeException(); });
frame.add(button);
frame.setSize(new Dimension(50, 50));
SwingUtilities.invokeLater(() -> frame.setVisible(true));
}
}
Así es como se ve en modo de depuración en Eclipse.