Question

Existe-t-il un moyen d'annoter une méthode afin que toutes les exceptions levées soient converties en exception d'exécution automatiquement?

@MagicAnnotation
// no throws clause!
void foo()
{
  throw new Exception("bar")'
}
Était-ce utile?

La solution

Pas moyen de faire ça, du moins pour l'instant j'utilise une solution de contournement comme celle-ci (simplifiée):

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

Le truc, c’est que l’interface est & "jamais fini &"; et chaque fois que j'ai besoin d'une méthode non contrôlée quelque part, je vais envelopper cet objet dans non vérifié et laisser l'IDE générer la signature de la méthode dans l'interface.

L'implémentation est alors générique (réfléchissante et & "lente &" mais généralement assez rapide)

.

Il y a des post-processeurs de code et des tisseurs de bytecode mais cela n’a pas été possible (pas même un langage basé sur jop / jop) pour mon projet actuel, donc cela a été & "; inventé &";.

Autres conseils

La @SneakyThrows du projet Lombok est probablement ce que vous recherchez. Ne constitue pas vraiment une exception pour votre exception (car cela peut être un problème dans de nombreux cas), cela ne génère pas une erreur lors de la compilation.

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

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

Modifier Pour en dire un peu plus à ce sujet:

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

Alors évidemment, le test ne va pas être compilé. Cela 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 indique en gros que tout code provenant d’un test (par exemple, une méthode commençant par & "test &"; dans une classe qui se termine par & "Test &"; et renvoie 'void') qui lève une exception devrait être accepté par le compilateur AspectJ. Si une exception se produit, elle sera encapsulée et renvoyée comme 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é), le test réussira, mais sans cet aspect, il ne sera même pas compilé.

Je pense que cela est possible avec la réingénierie du bytecode, un compilateur personnalisé ou peut-être une programmation orientée aspect 1 . Contrairement à Java, C # n’a que des exceptions non vérifiées 2 .

Puis-je vous demander pourquoi vous souhaitez supprimer les exceptions vérifiées?

1 selon Maarten Winkels , cela est possible.
2 et ils envisagent d’introduire ceux qui ont été cochés, selon certaines vidéos de Channel 9.

Modifier: Pour la question: il est possible d'annoter vos méthodes pour les signaler comme candidats à la suppression des exceptions vérifiées. Ensuite, vous utilisez des astuces de compilation ou d’exécution pour appliquer la suppression / wrapping réelle.

Cependant, comme je ne vois pas l'environnement dans votre cas, le fait d'exprimer une exception de cette façon pourrait dérouter les clients de cette méthode. Ils pourraient ne pas être prêts à gérer une exception RuntimeException. Par exemple: la méthode lève une exception IOException et vos clients l'interprètent comme une exception FileNotFoundException pour afficher une boîte de dialogue d'erreur. Cependant, si vous encapsulez votre exception dans une exception RuntimeException, la boîte de dialogue d'erreur ne sera jamais affichée et elle supprimera probablement le thread appelant également. (IMHO).

Les exceptions Checked sont responsables de l’implémentation de la méthode. Prenez très très attentivement ce fait. si vous ne pouvez pas utiliser des artefacts de contournement comme celui-ci.

Vous pouvez le faire dans tous les cas en utilisant le fait que Class.newInstance n'englobe pas un Exception lancé par le constructeur no-arg dans un InvocationTargetException; il le jette plutôt en 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;
      }
  }
}

Vous pouvez ensuite utiliser cet utilitaire n’importe où:

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

Au fait, c’est une très mauvaise idée : -)

J'utilise le système de complétion / modèle d'Eclipse pour envelopper 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); 
}

Avec Java 8, c’est aussi simple que: soften(() -> methodThatMayThrow())

Pour en savoir plus, consultez la http: //iirekm.blogspot. .com / 2014/05 / résoudre-problèmes-avec-java-vérifié.html

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top