Pregunta Uncatchable ChuckNorrisException


¿Es posible construir un fragmento de código en Java eso haría un hipotético java.lang.ChuckNorrisException ¿Incapturable?

Los pensamientos que se me ocurrieron son, por ejemplo, el uso de interceptores o Programación Orientada a Aspectos.


577
2017-12-14 17:05


origen


Respuestas:


No lo he intentado, así que no sé si JVM restringiría algo así, pero tal vez podrías compilar el código que arroja ChuckNorrisException, pero en el tiempo de ejecución proporciona una definición de clase de ChuckNorrisException cual no extiende Throwable.

ACTUALIZAR:

No funciona Genera un error de verificador:

Exception in thread "main" java.lang.VerifyError: (class: TestThrow, method: ma\
in signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestThrow.  Program will exit.

ACTUALIZACIÓN 2:

¡En realidad, puedes hacer que esto funcione si deshabilitas el verificador de código de bytes! (-Xverify:none)

ACTUALIZACIÓN 3:

Para aquellos que siguen desde casa, aquí está el guión completo:

Crea las siguientes clases:

public class ChuckNorrisException
    extends RuntimeException // <- Comment out this line on second compilation
{
    public ChuckNorrisException() { }
}

public class TestVillain {
    public static void main(String[] args) {
        try {
            throw new ChuckNorrisException();
        }
        catch(Throwable t) {
            System.out.println("Gotcha!");
        }
        finally {
            System.out.println("The end.");
        }
    }
}

Compilar clases:

javac -cp . TestVillain.java ChuckNorrisException.java

Correr:

java -cp . TestVillain
Gotcha!
The end.

Comenta "extiende RuntimeException" y recompilar ChuckNorrisException.java solamente :

javac -cp . ChuckNorrisException.java

Correr:

java -cp . TestVillain
Exception in thread "main" java.lang.VerifyError: (class: TestVillain, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
Could not find the main class: TestVillain.  Program will exit.

Ejecutar sin verificación:

java -Xverify:none -cp . TestVillain
The end.
Exception in thread "main"

305
2017-12-14 17:27



Después de haber reflexionado sobre esto, he creado con éxito una excepción que no se puede atrapar. Elegí nombrarlo JulesWinnfield, sin embargo, en lugar de Chuck, porque es una excepción de madre de puesta en la nube de hongos. Además, puede que no sea exactamente lo que tenía en mente, pero ciertamente no se puede atrapar. Observar:

public static class JulesWinnfield extends Exception
{
    JulesWinnfield()
    {
        System.err.println("Say 'What' again! I dare you! I double dare you!");
        System.exit(25-17); // And you shall know I am the LORD
    }
}


public static void main(String[] args)
{       
    try
    {
        throw new JulesWinnfield();
    } 
    catch(JulesWinnfield jw)
    {
        System.out.println("There's a word for that Jules - a bum");
    }
}

Et voila! Excepción no detectada.

Salida:

correr:

¡Dí que otra vez! ¡Yo Te reto! ¡Te recontra reto!

Resultado de Java: 8

CONSTRUIR ÉXITO (tiempo total: 0 segundos)

Cuando tenga un poco más de tiempo, veré si no puedo encontrar otra cosa, también.

Además, mira esto:

public static class JulesWinnfield extends Exception
{
    JulesWinnfield() throws JulesWinnfield, VincentVega
    {
        throw new VincentVega();
    }
}

public static class VincentVega extends Exception
{
    VincentVega() throws JulesWinnfield, VincentVega
    {
        throw new JulesWinnfield();
    }
}


public static void main(String[] args) throws VincentVega
{

    try
    {
        throw new JulesWinnfield();
    }
    catch(JulesWinnfield jw)
    {

    }
    catch(VincentVega vv)
    {

    }
}

Causa un desbordamiento de la pila. De nuevo, las excepciones no se detectan.


113
2017-12-15 12:16



Con tal excepción, obviamente sería obligatorio usar un System.exit(Integer.MIN_VALUE); del constructor porque esto es lo que pasaría si lanzases una excepción;)


84
2017-12-14 17:15



Cualquier código puede atrapar Throwable. Entonces, no, la excepción que crees va a ser una subclase de Throwable y estará sujeta a ser atrapada.


45
2017-12-14 17:09



public class ChuckNorrisException extends Exception {
    public ChuckNorrisException() {
        System.exit(1);
    }
}

(Concedido, técnicamente esta excepción nunca se arroja realmente, sino una verdadera ChuckNorrisException no se puede tirar, te tira primero).


34
2017-12-15 19:01



Cualquier excepción que arrojes tiene que extender Throwable, por lo que siempre se puede atrapar. Entonces la respuesta es no.

Si quiere dificultar su manejo, puede anular los métodos getCause(), getMessage(), getStackTrace(), toString() lanzar otro java.lang.ChuckNorrisException.


28
2017-12-14 17:17



Mi respuesta se basa en la idea de @ jtahlborn, pero funciona a pleno rendimiento Java programa, que puede ser empacado en una TARRO archivo e incluso implementado en su servidor de aplicaciones favorito como parte de un Aplicación web.

Antes que nada, definamos ChuckNorrisException clase para que no cuelgue JVM desde el principio (a Chuck le encanta chocar JVMs BTW :)

package chuck;

import java.io.PrintStream;
import java.io.PrintWriter;

public class ChuckNorrisException extends Exception {

    public ChuckNorrisException() {
    }

    @Override
    public Throwable getCause() {
        return null;
    }

    @Override
    public String getMessage() {
        return toString();
    }

    @Override
    public void printStackTrace(PrintWriter s) {
        super.printStackTrace(s);
    }

    @Override
    public void printStackTrace(PrintStream s) {
        super.printStackTrace(s);
    }
}

Ahora va Expendables clase para construirlo:

package chuck;

import javassist.*;

public class Expendables {

    private static Class clz;

    public static ChuckNorrisException getChuck() {
        try {
            if (clz == null) {
                ClassPool pool = ClassPool.getDefault();
                CtClass cc = pool.get("chuck.ChuckNorrisException");
                cc.setSuperclass(pool.get("java.lang.Object"));
                clz = cc.toClass();
            }
            return (ChuckNorrisException)clz.newInstance();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

Y finalmente el Main clase para patear algunos traseros:

package chuck;

public class Main {

    public void roundhouseKick() throws Exception {
        throw Expendables.getChuck();
    }

    public void foo() {
        try {
            roundhouseKick();
        } catch (Throwable ex) {
            System.out.println("Caught " + ex.toString());
        }
    }

    public static void main(String[] args) {
        try {
            System.out.println("before");
            new Main().foo();
            System.out.println("after");
        } finally {
            System.out.println("finally");
        }
    }
}

Compilar y ejecutarlo con el siguiente comando:

java -Xverify:none -cp .:<path_to_javassist-3.9.0.GA.jar> chuck.Main

Obtendrás el siguiente resultado:

before
finally

No es de extrañar, es una patada redonda después de todo :)


23
2017-12-18 22:56



En el constructor puede iniciar un hilo que llama repetidamente originalThread.stop (ChuckNorisException.this) 

El hilo podría atrapar la excepción repetidamente pero seguiría arrojándola hasta que muera.


15
2017-12-14 20:55



No. Todas las excepciones en Java deben subclase java.lang.Throwable, y aunque puede que no sea una buena práctica, puedes detectar todo tipo de excepción como esta:

try {
    //Stuff
} catch ( Throwable T ){
    //Doesn't matter what it was, I caught it.
}

Ver el java.lang.Throwable documentación para más información.

Si estás tratando de evitar excepciones marcadas (los que deben manejarse explícitamente), entonces querrá subclasar Error o RuntimeException.


13
2017-12-14 17:09



Una variante del tema es el hecho sorprendente de que puedes lanzar excepciones comprobadas no declaradas desde el código de Java. Como no está declarado en la firma de métodos, el compilador no le permitirá capturar la excepción en sí, aunque puede atraparla como java.lang.Exception.

Aquí hay una clase de ayuda que te permite arrojar cualquier cosa, declarada o no:

public class SneakyThrow {
  public static RuntimeException sneak(Throwable t) {
    throw SneakyThrow.<RuntimeException> throwGivenThrowable(t);
  }

  private static <T extends Throwable> RuntimeException throwGivenThrowable(Throwable t) throws T {
    throw (T) t;
  }
}

Ahora throw SneakyThrow.sneak(new ChuckNorrisException()); Lanza una ChuckNorrisException, pero el compilador se queja de

try {
  throw SneakyThrow.sneak(new ChuckNorrisException());
} catch (ChuckNorrisException e) {
}

sobre capturar una excepción que no se lanza si ChuckNorrisException es una excepción marcada.


8
2017-12-22 08:32



En realidad, la respuesta aceptada no es tan buena porque Java debe ejecutarse sin verificación, es decir, el código no funcionaría en circunstancias normales.

AspectJ al rescate para el solución real!

Clase de excepción:

package de.scrum_master.app;

public class ChuckNorrisException extends RuntimeException {
    public ChuckNorrisException(String message) {
        super(message);
    }
}

Aspecto:

package de.scrum_master.aspect;

import de.scrum_master.app.ChuckNorrisException;

public aspect ChuckNorrisAspect {
    before(ChuckNorrisException chuck) : handler(*) && args(chuck) {
        System.out.println("Somebody is trying to catch Chuck Norris - LOL!");
        throw chuck;
    }
}

Aplicación de muestra:

package de.scrum_master.app;

public class Application {
    public static void main(String[] args) {
        catchAllMethod();
    }

    private static void catchAllMethod() {
        try {
            exceptionThrowingMethod();
        }
        catch (Throwable t) {
            System.out.println("Gotcha, " + t.getClass().getSimpleName() + "!");
        }
    }

    private static void exceptionThrowingMethod() {
        throw new ChuckNorrisException("Catch me if you can!");
    }
}

Salida:

Somebody is trying to catch Chuck Norris - LOL!
Exception in thread "main" de.scrum_master.app.ChuckNorrisException: Catch me if you can!
    at de.scrum_master.app.Application.exceptionThrowingMethod(Application.java:18)
    at de.scrum_master.app.Application.catchAllMethod(Application.java:10)
    at de.scrum_master.app.Application.main(Application.java:5)

8
2018-04-19 10:42