Pregunta

¿Hay alguna forma de anotar un método para que todas las excepciones lanzadas se conviertan automáticamente en excepciones de tiempo de ejecución?

@MagicAnnotation
// no throws clause!
void foo()
{
  throw new Exception("bar")'
}
¿Fue útil?

Solución

No hay forma de hacerlo, al menos por ahora utilizo una solución como esta (simplificada):

@SuppressWarnings({"rawtypes", "unchecked"})
public class Unchecked {
    public static interface UncheckedDefinitions{
        InputStream openStream();
        String readLine();
            ...
    }

  private static Class proxyClass = Proxy.getProxyClass(Unchecked.class.getClassLoader(), UncheckedDefinitions.class);

    public static UncheckedDefinitions unchecked(final Object target){
        try{
            return (UncheckedDefinitions) proxyClass.getConstructor(InvocationHandler.class).newInstance(new InvocationHandler(){
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    if (target instanceof Class){
                        return MethodUtils.invokeExactStaticMethod((Class) target, method.getName(), args);
                    }

                  return MethodUtils.invokeExactMethod(target, method.getName(), args);
                }
            });
        }
        catch(Exception e){
            throw new RuntimeException(e);
        }
    }
}

Y el uso se ve así:

import static ....Unchecked.*;

...

Writer w = ...;
unchecked(w).write(str, off, len);

El truco es que la interfaz es " nunca terminó " y cada vez que necesite un método sin marcar en alguna parte, envolveré ese objeto en sin marcar y dejaré que IDE genere la firma del método en la interfaz.

La implementación es genérica (reflexiva y " lenta " pero generalmente lo suficientemente rápida)

Hay algunos postprocesadores de código y tejedores de códigos de bytes, pero esto no fue posible (ni siquiera aop u otro lenguaje basado en jvm) para mi proyecto actual, así que esto fue " inventado ".

Otros consejos

Project Lombok's @SneakyThrows es probablemente lo que está buscando. Realmente no está envolviendo su excepción (porque puede ser un problema en muchos casos), simplemente no arroja un error durante la compilación.

@SneakyThrows
void foo() {
    throw new Exception("bar")'
}

Puedes hacer esto con AspectJ. Usted declara un punto de unión (en este caso, la invocación del método foo) y 'suaviza' la excepción.

Editar Para elaborar un poco sobre esto:

Digamos que tiene la siguiente clase Bar:

public class Bar {

    public void foo() throws Exception {
    }
}

... y tienes una prueba como esta:

import junit.framework.TestCase;

public class BarTest extends TestCase {

    public void testTestFoo() {
        new Bar().foo();
    }
}

Entonces, obviamente, la prueba no se compilará. Dará un error:

Unhandled exception type Exception  BarTest.java(line 6)

Ahora para superar esto con AspectJ, escribes un aspecto muy simple:

public aspect SoftenExceptionsInTestCode {

    pointcut inTestCode() : execution(void *Test.test*());

    declare soft : Exception : inTestCode();
}

El aspecto básicamente dice que cualquier código desde una Prueba (es decir: un método que comienza con " test " en una clase que termina en " Test " y devuelve 'nulo') que arroja una excepción debe ser aceptado por el compilador de AspectJ. Si ocurre una excepción, el compilador de AspectJ la envolverá y lanzará como RuntimeException.

De hecho, si ejecuta esta prueba como parte de un proyecto de AspectJ desde Eclipse (con AJDT instalado), la prueba tendrá éxito, mientras que sin el aspecto ni siquiera se compilará.

Creo que es posible con la reingeniería de bytecode, el compilador personalizado o quizás la programación orientada a aspectos 1 . Al contrario de Java, C # solo tiene excepciones sin marcar 2 .

¿Puedo preguntar por qué quiere suprimir las excepciones marcadas?

1 según Maarten Winkels esto es posible.
2 y están pensando en introducir los marcados, de acuerdo con algunos videos del Canal 9.

Editar: para la pregunta: es posible en el sentido de que puede anotar sus métodos para marcarlos como candidatos para la supresión de excepciones comprobada. Luego usa algún tiempo de compilación o truco de tiempo de ejecución para aplicar la supresión / ajuste real.

Sin embargo, como no veo el entorno de su caso, envolver una excepción de esta manera podría confundir a los clientes de ese método; es posible que no estén preparados para lidiar con una RuntimeException. Por ejemplo: el método arroja una IOException y sus clientes la capturan como FileNotFoundException para mostrar un diálogo de error. Sin embargo, si envuelve su excepción en una RuntimeException, el cuadro de diálogo de error nunca se muestra y probablemente también mata el hilo de la persona que llama. (En mi humilde opinión).

Las excepciones marcadas son responsabilidad de la implementación del método. Toma muy, muy cuidadosamente este hecho. si no puede usar artefactos alternativos como ese.

Puede hacer esto en cualquier caso mediante el uso del hecho de que Class.newInstance no envuelve un Exception lanzado por el constructor sin argumentos en un InvocationTargetException; más bien lo arroja en silencio :

class ExUtil {
  public static void throwSilent(Exception e) { //NOTICE NO THROWS CLAUSE
      tl.set(e);
      SilentThrower.class.newInstance(); //throws silently
  }

  private static ThreadLocal<Exception> tl = new ThreadLocal<Exception>();
  private static class SilentThrower {
      SilentThrower() throws Exception {
          Exception e = tl.get();
          tl.remove();
          throw e;
      }
  }
}

Entonces puede usar esta utilidad en cualquier lugar:

ExUtil.throwSilent(new Exception());
//or
try {
  ioMethod();
} catch (IOException e) { ExUtil.throwSilent(e); }

Por cierto, esta es una muy mala idea :-)

Utilizo el sistema de finalización / plantilla de Eclipse para envolver cualquier bloque de código fácilmente.

Aquí está mi plantilla:

try { // Wrapp exceptions

${line_selection}${cursor}

} catch (RuntimeException e) { // Forward runtime exception
throw e;
} catch (Exception e) { // Wrap into runtime exception
throw new RuntimeException(
    "Exception wrapped in #${enclosing_method}", 
    e); 
}

Con Java 8 es tan fácil como: soften(() -> methodThatMayThrow())

Lea más en http: //iirekm.blogspot .com / 2014/05 / fix-problems-with-java-checked.html

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top