Pergunta

Existe uma maneira de anotar um método para que todas as exceções lançadas são convertidos em tempo de execução exceção automagicamente?

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

Solução

Não há forma de fazer isso, pelo menos por agora eu uso solução como esta (simplificado):

@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);
        }
    }
}

e os olhares de uso como:

import static ....Unchecked.*;

...

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

O truque é que a interface é "nunca terminou" e sempre que eu preciso método desmarcada em algum lugar, eu vou quebrar esse objeto em desmarcada e deixe IDE gerar assinatura do método na interface.

A implementação é seguida genérico (reflexivo e "lento", mas geralmente rápido o suficiente)

Há alguns código de pós-processadores e bytecode tecelões, mas isso não era possível (nem mesmo AOP ou outra linguagem baseada JVM) para o meu projeto atual, de modo que este foi "inventado".

Outras dicas

O @SneakyThrows Projeto Lombok é provavelmente o que você está procurando. não é realmente envolvendo sua exceção (porque pode ser um problema em muitos casos), ele simplesmente não lançar um erro durante a compilação.

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

Você pode fazer isso com AspectJ. Você declarar uma joinpoint (neste caso, a invocação do foo método) e 'suavizar' a exceção.

Editar Para elaborar um pouco sobre isso:

Digamos que você tenha o seguinte Bar classe:

public class Bar {

    public void foo() throws Exception {
    }
}

... e você tem um teste como este:

import junit.framework.TestCase;

public class BarTest extends TestCase {

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

Então, obviamente, o teste não vai compilar. Ele lhe dará um erro:

Unhandled exception type Exception  BarTest.java(line 6)

Agora, para superar isso com AspectJ, você escreve um aspecto muito simples:

public aspect SoftenExceptionsInTestCode {

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

    declare soft : Exception : inTestCode();
}

O aspecto basicamente diz que qualquer código de dentro de um teste (ou seja: um método que começa com "teste" em uma classe que termina em "teste" e retorna 'vazio') que gera uma exceção deve ser aceito pelo AspectJ compilador. Se ocorrer uma exceção, ela será embrulhado e jogado como um RuntimeException pelo compilador AspectJ.

Na verdade, se você executar este teste como parte de um projeto AspectJ de dentro do Eclipse (com AJDT instalado), em seguida, o teste será bem-sucedida, enquanto que sem o aspecto que não vai mesmo compilar.

Eu acho que é possível com bytecode re-engenharia, compilador personalizado ou talvez orientada a aspectos de programação 1 . Na ao contrário do Java, C # tem exceções única desmarcada 2 .

Posso perguntar por que você quer para suprimir a exceções verificadas?

1 de acordo com Maarten Winkels isso é possível.
2 e eles estão pensando em introduzir os verificados, de acordo com alguns Canal 9 vídeos.

Editar: Para a pergunta: é possível no sentido de que você pode anotar seus métodos de bandeira-los para ser um candidato para a supressão de exceção verificada. Então você usar algum tempo de compilação ou truque de tempo de execução para aplicar o actual supressão / embalagem.

No entanto, como eu não ver o ambiente em torno do seu caso, envolvendo uma exceção dessas formas pode confundir os clientes desse método - que não pode estar preparado para lidar com uma RuntimeException. Por exemplo: o método lança uma IOException e seus clientes pega-lo como FileNotFoundException para exibir um diálogo de erro. No entanto, se você quebrar sua exceção em um RuntimeException, o diálogo de erro nunca é mostrado e, provavelmente, ele mata o fio chamador também. (IMHO).

As exceções verificadas são da responsabilidade da implementação do método. Tome muito cuidado este fato. se você pode não usar solução alternativa artefatos assim.

Você pode fazer isso em qualquer caso, via uso do fato de que Class.newInstance não embrulhar um Exception lançada pelo construtor sem argumento em uma InvocationTargetException; em vez disso, joga silenciosamente :

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

Em seguida, você pode usar isso em qualquer lugar utilitário:

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

A propósito, este é uma péssima idéia : -)

Eu uso o sistema de conclusão / template de Eclipse para embrulhar qualquer bloco de código facilmente.

Aqui está o meu template:

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); 
}

Com Java 8 é tão fácil como: soften(() -> methodThatMayThrow())

Leia mais em http: //iirekm.blogspot .com / 2014/05 / fix-problemas-com-java-checked.html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top