Domanda

Esiste un modo per annotare un metodo in modo che tutte le eccezioni generate vengano convertite automaticamente in eccezione di runtime?

@MagicAnnotation
// no throws clause!
void foo()
{
  throw new Exception("bar")'
}
È stato utile?

Soluzione

Non c'è modo di farlo, almeno per ora uso questa soluzione alternativa (semplificata):

@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 l'uso appare come:

import static ....Unchecked.*;

...

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

Il trucco è che l'interfaccia è " mai finita " e ogni volta che avrò bisogno di un metodo non controllato da qualche parte, avvolgerò quell'oggetto in non selezionato e lascerò che IDE generi la firma del metodo nell'interfaccia.

L'implementazione è quindi generica (riflettente e " slow " ma di solito abbastanza veloce)

Ci sono alcuni post-processori di codice e tessitori di bytecode ma questo non era possibile (nemmeno aop o altro linguaggio basato su jvm) per il mio progetto attuale, quindi questo era " inventato ".

Altri suggerimenti

Il progetto @SneakyThrows di Project Lombok è probabilmente ciò che stai cercando. Non sta davvero avvolgendo la tua eccezione (perché può essere un problema in molti casi), semplicemente non genera un errore durante la compilazione.

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

Puoi farlo con AspectJ. Dichiarate un joinpoint (in questo caso invocazione del metodo foo) e "attenuate" l'eccezione.

Modifica Per approfondire un po ':

Supponi di avere la seguente classe Bar:

public class Bar {

    public void foo() throws Exception {
    }
}

... e hai un test come questo:

import junit.framework.TestCase;

public class BarTest extends TestCase {

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

Quindi ovviamente il test non verrà compilato. Darà un errore:

Unhandled exception type Exception  BarTest.java(line 6)

Ora per ovviare a questo con AspectJ, scrivi un aspetto molto semplice:

public aspect SoftenExceptionsInTestCode {

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

    declare soft : Exception : inTestCode();
}

L'aspetto sostanzialmente dice che qualsiasi codice all'interno di un Test (cioè: un metodo che inizia con " test " in una classe che termina in " Test " e restituisce 'void') che genera un'eccezione dovrebbe essere accettato dal compilatore AspectJ. Se si verifica un'eccezione, verrà racchiusa e lanciata come RuntimeException dal compilatore AspectJ.

In effetti, se si esegue questo test come parte di un progetto AspectJ all'interno di Eclipse (con AJDT installato), il test avrà esito positivo, mentre senza l'aspetto non verrà nemmeno compilato.

Penso che sia possibile con la riprogettazione del bytecode, il compilatore personalizzato o forse la programmazione orientata all'aspetto 1 . Al contrario di Java, C # ha solo deselezionate le eccezioni 2 .

Posso chiederti perché vuoi sopprimere le eccezioni selezionate?

1 secondo Maarten Winkels questo è possibile.
2 e stanno pensando di introdurre quelli controllati, secondo alcuni video di Channel 9.

Modifica: Per la domanda: è possibile nel senso che è possibile annotare i metodi per contrassegnarli come candidati alla soppressione delle eccezioni verificata. Quindi si utilizza un po 'di tempo di compilazione o trucco di runtime per applicare la soppressione / wrapping effettiva.

Tuttavia, poiché non vedo l'ambiente intorno al tuo caso, racchiudere un'eccezione in questi modi potrebbe confondere i client di quel metodo - potrebbero non essere pronti a gestire una RuntimeException. Ad esempio: il metodo genera una IOException e i client la catturano come FileNotFoundException per visualizzare una finestra di dialogo di errore. Tuttavia, se racchiudi l'eccezione in RuntimeException, la finestra di dialogo di errore non viene mai visualizzata e probabilmente uccide anche il thread del chiamante. (IMHO).

Le eccezioni verificate sono responsabili dell'implementazione del metodo. Prendi molto attentamente questo fatto. se non riesci a usare artefatti di questo tipo.

Puoi farlo in ogni caso usando il fatto che Class.newInstance non avvolge un Exception lanciato dal costruttore no-arg in un InvocationTargetException; piuttosto lo lancia silenziosamente :

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

Quindi puoi usare questa utility ovunque:

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

A proposito, questa è una pessima idea :-)

Uso il sistema di completamento / modello di Eclipse per avvolgere facilmente qualsiasi blocco di codice.

Ecco il mio modello:

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 è facile come: soften(() -> methodThatMayThrow())

Ulteriori informazioni su http: //iirekm.blogspot .com / 2014/05 / fix-problemi-con-java-checked.html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top