2009-06-27 12 views
8

Gibt es eine Möglichkeit, eine Methode mit Anmerkungen zu versehen, sodass alle ausgelösten Ausnahmen automatisch in die Laufzeitausnahme konvertiert werden?Wrap-Ausnahmen durch Laufzeitausnahmen mit einer Anmerkung

@MagicAnnotation 
// no throws clause! 
void foo() 
{ 
    throw new Exception("bar")' 
} 
+1

einen Weg IOW die Compiler-Kontrollen überprüft Ausnahmen auszuschalten. –

+0

Ja - ich glaube ich habe das irgendwo gesehen, sogar in unserer eigenen Codebasis. – ripper234

Antwort

1

Keine Weise zu tun, dass, zumindest für jetzt wie folgt ich Abhilfe verwenden (vereinfacht):

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

Und die Nutzung wie folgt aussieht:

import static ....Unchecked.*; 

... 

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

Der Trick, dass Schnittstelle ist " nie beendet "und jedes Mal, wenn ich irgendwo unkontrollierte Methode brauche, werde ich das Objekt in unchecked und lassen Sie IDE Methodensignatur in der Schnittstelle generieren.

Die Umsetzung ist dann generisch (reflektierende und „langsam“, aber in der Regel schnell genug)

Es gibt einige Code Postprozessoren und Bytecode-Weber aber das war nicht möglich (auch nicht aop oder andere Jvm basierte Sprache) für mein aktuelles Projekt, also wurde das "erfunden".

2

Sie können dies mit AspectJ tun. Sie deklarieren einen Joinpoint (in diesem Fall Aufruf der Methode foo) und "mildern" Sie die Ausnahme.

bearbeiten Um ein wenig näher darauf eingehen:

Sagen Sie bitte die folgende Klasse Bar haben:

public class Bar { 

    public void foo() throws Exception { 
    } 
} 

... und Sie haben ein Test wie folgt aus:

import junit.framework.TestCase; 

public class BarTest extends TestCase { 

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

Dann wird natürlich der Test nicht kompilieren. Es wird einen Fehler geben:

Unhandled exception type Exception BarTest.java(line 6) 

Nun ist diesen mit AspectJ zu überwinden, schreiben Sie einen sehr einfachen Aspekt: ​​

public aspect SoftenExceptionsInTestCode { 

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

    declare soft : Exception : inTestCode(); 
} 

Der Aspekt im Grunde sagt, dass jeder Code aus einem Test (das heißt: ein Verfahren, das beginnt mit "Test" in einer Klasse, die mit "Test" endet und "void" zurückgibt), die eine Ausnahme auslöst, sollte vom AspectJ-Compiler akzeptiert werden. Wenn eine Ausnahme auftritt, wird sie vom AspectJ-Compiler umbrochen und als RuntimeException geworfen.

In der Tat, wenn Sie diesen Test als Teil eines AspectJ Projekts aus Eclipse (mit AJDT installiert), dann wird der Test erfolgreich sein, während ohne den Aspekt wird es nicht sogar kompilieren.

+0

Ich denke, das ist eine faire Antwort (obwohl ich neben den Konzepten nichts über AOP weiß). Ich frage mich, warum es abgelehnt wurde? – akarnokd

+0

Beispielcode wäre sehr schön - es gibt viele neue Konzepte, wenn man auf AOP schaut, die schwer zu bekommen sind. –

1

Ich denke, dass es mit Bytecode Reengineering, benutzerdefinierten Compiler oder Aspect-orientierte Programmierung möglich ist. Im Gegensatz zu Java hat C# nur die Ausnahmen deaktiviert.

Darf ich fragen, warum Sie die geprüften Ausnahmen unterdrücken möchten?

nach Maarten Winkels dies ist möglich.
und sie denken über die Einführung geprüft, nach einigen Channel 9 Videos.

Bearbeiten: Für die Frage: Es ist in dem Sinne möglich, dass Sie Ihre Methoden mit Anmerkungen versehen können, um sie als Kandidaten für die Überprüfung der Ausnahmebedingung zu markieren. Dann verwenden Sie einige Kompilierzeit oder Runtime-Trick, um die tatsächliche Unterdrückung/Umbruch anzuwenden.

Da jedoch die Umgebung in Ihrem Fall nicht angezeigt wird, kann das Umbrechen einer Ausnahme auf diese Weise die Clients dieser Methode verwirren - sie sind möglicherweise nicht auf eine RuntimeException vorbereitet. Beispiel: Die Methode löst eine IOException aus, und Ihre Clients fangen sie als FileNotFoundException ab, um einen Fehlerdialog anzuzeigen. Wenn Sie jedoch Ihre Exception in eine RuntimeException umbrechen, wird der Fehlerdialog nie angezeigt, und wahrscheinlich wird auch der Thread des Aufrufers beendet. (MEINER BESCHEIDENEN MEINUNG NACH).

+0

Testcode, es interessiert mich nicht wirklich welche Ausnahmen zu diesem Zeitpunkt. Auch meine Aufnahme in die checked-Exceptions-yes-or-no ist eine ziemlich solide Nein (aber wird Standard entsprechen und nicht alle meine Ausnahmen RuntimeException für Produktionscode erweitern). – ripper234

+0

Danke. Ich denke, dass die Option zur Überprüfung der Verwendung aktiviert ist - es ermöglicht Ihnen, Ihre Kunden zu "führen".Manchmal empfinde ich es aber auch, dass in einigen besonderen Fällen eine Ausnahme der andere Typ sein sollte. Auf konzeptioneller Ebene denke ich, dass meine Antwort immer noch steht. – akarnokd

0

Sie können dies von der Tatsache, über die Verwendung in jedem Fall tun, dass Class.newInstancenicht ein Exception durch den nicht-arg Konstruktor in einem InvocationTargetException geworfen wickeln; vielmehr wirft sie es still:

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

Dann können Sie dieses Dienstprogramm überall verwenden:

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

By the way, ist dies eine wirklich schlechte Idee :-)

0

I Verwenden Sie das Vervollständigungs-/Vorlagensystem von Eclipse, um einen beliebigen Codeblock einfach zu umbrechen.

Hier ist meine Vorlage:

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

Die Checked Ausnahmen keinerlei Gewährleistung der Verfahrensführung sind. Nehmen Sie sehr genau diese Tatsache. Wenn Sie keine Workaround-Artefakte wie diese verwenden können.

6

Projekt Lombok's @SneakyThrows ist wahrscheinlich das, was Sie suchen. Umschließt Ihre Exception nicht wirklich (weil es in vielen Fällen ein Problem sein kann), es wirft nur keinen Fehler während der Kompilierung.

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