2009-06-27 15 views
8

Existe-t-il un moyen d'annoter une méthode afin que toutes les exceptions générées soient converties automatiquement en exception d'exécution?Reprise des exceptions par des exceptions d'exécution avec une annotation

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

OIEau un moyen de désactiver les contrôles du compilateur sur les exceptions vérifiées. –

+0

Oui - Je pense que j'ai vu quelque part, même dans notre propre base de code. – ripper234

Répondre

1

Aucun moyen de le faire, au moins pour l'instant j'utilise solution de contournement comme ceci (simplifié):

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

Et l'utilisation ressemble à:

import static ....Unchecked.*; 

... 

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

L'astuce est que l'interface est " jamais fini »et chaque fois que j'ai besoin d'une méthode non cochée quelque part, je vais envelopper cet objet dans non cochée et laisser IDE générer la signature de la méthode dans l'interface.

La mise en œuvre est alors générique (réflexion et « lent », mais généralement assez rapide)

Il y a des post-processeurs code et bytecode-tisserands, mais cela n'a pas été possible (même pas aop ou autre langue à base de jvm) pour mon projet actuel, donc c'était "inventé".

2

Vous pouvez le faire avec AspectJ. Vous déclarez un jointure (dans ce cas, invocation de la méthode foo) et "assouplissez" l'exception.

Modifier Pour élaborer un peu sur ce point:

Supposons que vous avez la classe suivante Bar:

public class Bar { 

    public void foo() throws Exception { 
    } 
} 

... et vous avez un test comme celui-ci:

import junit.framework.TestCase; 

public class BarTest extends TestCase { 

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

Ensuite, évidemment, le test ne va pas compiler. Il donnera une erreur:

Unhandled exception type Exception BarTest.java(line 6) 

Maintenant, pour surmonter cela avec AspectJ, vous écrivez un aspect très simple:

public aspect SoftenExceptionsInTestCode { 

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

    declare soft : Exception : inTestCode(); 
} 

L'aspect dit essentiellement que tout code à partir d'un test (ex: une méthode qui commence par "test" dans une classe qui se termine par "Test" et retourne "void") qui déclenche une exception devrait être acceptée par le compilateur AspectJ. Si une exception se produit, elle sera enveloppée et renvoyée en tant que RuntimeException par le compilateur AspectJ.

En effet, si vous exécutez ce test dans le cadre d'un projet AspectJ à partir d'Eclipse (avec AJDT installé), alors le test réussira, alors que sans l'aspect, il ne sera même pas compilé.

+0

Je pense que c'est une réponse juste (bien que je ne sache rien à propos de l'AOP en dehors des concepts). Je me demande pourquoi il a été downvoted? – akarnokd

+0

Exemple de code serait très agréable - il y a beaucoup de nouveaux concepts en regardant sur AOP qui est difficile à obtenir correctement. –

1

Je pense que c'est possible avec la reconfiguration bytecode, le compilateur personnalisé ou peut-être la programmation orientée aspect . Contrairement à Java, C# n'a que des exceptions non contrôlées . Puis-je vous demander pourquoi vous souhaitez supprimer les exceptions vérifiées?

selon Maarten Winkels cela est possible.
et ils envisagent d'introduire ceux vérifiés, selon certaines vidéos Channel 9.

Editer: Pour la question: Il est possible dans le sens où vous pouvez annoter vos méthodes pour les signaler comme candidat à la suppression d'exception vérifiée. Ensuite, vous utilisez une astuce de compilation ou d'exécution pour appliquer la suppression/l'enrobage. Cependant, comme je ne vois pas l'environnement autour de votre cas, le fait d'enrouler une exception de cette manière peut dérouter les clients de cette méthode - ils ne sont peut-être pas prêts à gérer une exception RuntimeException. Par exemple: la méthode lance une IOException et vos clients l'attrape comme FileNotFoundException pour afficher une boîte de dialogue d'erreur. Toutefois, si vous intégrez votre exception dans une exception RuntimeException, la boîte de dialogue d'erreur n'est jamais affichée et elle tue probablement le thread appelant. (A MON HUMBLE AVIS).

+0

Code de test, je ne me soucie pas vraiment des exceptions à ce moment-là. En outre, ma prise dans les check-exceptions-oui-ou-non est un non assez solide (mais sera conforme à la norme et ne pas toutes mes exceptions étendent RuntimeException pour le code de production). – ripper234

+0

Merci. Je pense que l'option d'utilisation de l'exception vérifiée est bonne - elle vous permet de «guider» vos clients.Cependant, je le sens parfois aussi, dans certains cas particuliers, qu'une exception aurait dû être l'autre type. Cependant, sur le plan conceptuel, je pense que ma réponse est toujours là. – akarnokd

0

Vous pouvez le faire en tout cas, via l'utilisation du fait que Class.newInstancen'a pas enveloppe un Exception jeté par le constructeur sans arg dans un InvocationTargetException; plutôt jette silence:

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

Ensuite, vous pouvez utiliser cet utilitaire partout:

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

Soit dit en passant, c'est une très mauvaise idée :-)

0

I utilisez le système de complétion/modèle d'Eclipse pour emballer facilement n'importe quel bloc de code.

Voici mon modèle:

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

Les exceptions sont cochés de la responsabilité mise en œuvre de la méthode. Prenez très très attentivement ce fait. Si vous ne pouvez pas utiliser des artefacts de contournement comme ça.

6

Le projet Lombok's @SneakyThrows est probablement ce que vous cherchez. N'enveloppe pas vraiment votre exception (car cela peut être un problème dans beaucoup de cas), cela ne génère pas d'erreur lors de la compilation.

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