2012-08-13 18 views
17

Tengo un método como este:Cómo lanzar una excepción cuando la firma de su método no permite lanzar Exception?

public void getSomething(){ 
... 
} 

Quiero lanzar una Exception dentro getSomething(). El compilador no me permitirá hacer eso porque mi método no permite que se entregue Exception allí. Pero necesito lanzar una subclase de Exception para mi prueba (no puedo lanzar 0-)). Esto es claramente un truco, pero lo necesito para mi prueba. Intenté EasyMock pero tampoco me permite hacer eso. Alguna idea de como hacer eso?

Gracias, Sean Nguyen

+0

caso está probando algo que es imposible que suceda. ¿Por qué? – rodrigoap

+0

Intenté simular la respuesta del jabón con LogicalHandler . El handleMessage (contexto LogicalMessageContext) no declara throws Exception. Pero todas las excepciones lanzadas por el punto final del jabón son subclase de Excepciones. Necesito arrojar esas excepciones para burlar mi respuesta de servicio. –

+0

Ver mi edición en caso de que esté interesado. –

Respuesta

19

Método 1:

This post by Alexey Ragozin describe cómo utilizar un truco de los genéricos a lanzar una excepción comprobada no declarado. A partir de ese mensaje:

public class AnyThrow { 

    public static void throwUnchecked(Throwable e) { 
     AnyThrow.<RuntimeException>throwAny(e); 
    } 

    @SuppressWarnings("unchecked") 
    private static <E extends Throwable> void throwAny(Throwable e) throws E { 
     throw (E)e; 
    } 
} 

El truco se basa en throwUnchecked "mentir" al compilador que el tipo E es RuntimeException con su llamada a throwAny. Dado que throwAny se declara como throws E, el compilador cree que una llamada en particular puede arrojar RuntimeException. Por supuesto, el truco es posible gracias al throwAny que declara arbitrariamente E y lo lanza ciegamente, lo que le permite a la persona que llama decidir cuál es su argumento: terrible diseño cuando se codifica sanamente. En tiempo de ejecución, E es erased y no tiene ningún significado.

Como ha señalado, hacer tal cosa es un gran hack y debe documentar su uso muy bien.


Método 2:

También puede utilizar sun.misc.Unsafe a este fin. En primer lugar se debe implementar un método que utiliza la reflexión para volver instancia de esa clase:

private static Unsafe getUnsafe() { 
    try { 
     Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); 
     theUnsafeField.setAccessible(true); 
     return (Unsafe)theUnsafeField.get(null); 
    } 
    catch (NoSuchFieldException e) { 
     throw new RuntimeException(e); 
    } 
    catch (IllegalAccessException e) { 
     throw new RuntimeException(e); 
    } 
} 

Esto es necesario como llamar Unsafe.getUnsafe() normalmente arrojará una SecurityException. Una vez que tenga la instancia de Unsafe puede poner sus capacidades terribles a utilizar:

Unsafe unsafe = getUnsafe(); 
unsafe.throwException(new Exception()); 

mérito es de this answer en el puesto https://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe.Pensé que mencionaría esto como completo, pero probablemente sea mejor usar el truco anterior en lugar de permitir Unsafe en tu código.


Método 3:

En los comentarios de la respuesta relacionado sobre el uso de Unsafe, @bestsss points out un truco mucho más simple utilizando el método obsoleto Thread.stop(Throwable):

Thread.currentThread().stop(new Exception()); 

En este caso lo haría use @SuppressWarnings("deprecation") y una vez más documente con mucha fiereza. De nuevo, prefiero el primer truco para su limpieza (relativa).

+0

muchas gracias. ¡funciona! –

+0

@PaulBellora siempre puedes jugar con el método 'Class :: newInstance()', que arrojará cualquier cosa que haga el ctor – emesx

+0

@PaulBellora ¿Por qué el primer ejemplo no da como resultado 'ClassCastException' en tiempo de ejecución? – Demi

1

Java tiene dos tipos de excepciones, marcado y sin marcar. Debe declarar excepciones marcadas, pero no tiene que declarar excepciones sin marcar.

RuntimeException es la excepción básica sin marcar, por lo que puede lanzar eso sin declararlo.

public void getSomething(){ 
    throw new RuntimeException("I don't have to be declared in the method header!"); 
} 

Como nota al margen, es probable que no quieren lanzar una RuntimeException crudo, pero subclase a algo más específico para sus necesidades. Cualquier subclase de RuntimeException también será desmarcada.

+0

Lo siento por no ser claro. Necesito arrojar una subclase de java.lang.Exception (excepción comprobada). –

+3

@SeanNguyen RuntimeException es una subclase de Excepción. Es solo un caso especial en Java donde no necesita declarar que será lanzado. – Oleksi

+0

Lo siento, no muy claro de nuevo. Necesito arrojar una excepción marcada que sea una subclase de Excepción. No puedo lanzar RuntimeException. –

0

No sé lo que estabas tratando de hacer. Simplemente podría lanzar una excepción sin marcar dentro de su método y luego probar usando JUnit como en mi ejemplo a continuación.

public void getSomething() { 
    throw new RuntimeException(); 
} 

JUnit ejemplo de prueba 4:

@Test 
public void testGetSomething() { 
    try { 
     getSomething(); 
     fail("Expecting RuntimeException!"); 
    } catch (Exception e) { 
     Logger.getLogger("test").info("Exception was caught: " + e.getClass()); 
    } 
} 
Cuestiones relacionadas