Обернуть исключения во время выполнения исключениями с аннотацией - PullRequest
8 голосов
/ 27 июня 2009

Есть ли способ аннотировать метод, чтобы все выброшенные исключения автоматически конвертировались в исключение времени выполнения?

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

Ответы [ 8 ]

6 голосов
/ 30 ноября 2012

Project Lombok @SneakyThrows, вероятно, то, что вы ищете. На самом деле не оборачивает ваше исключение (потому что это может быть проблемой во многих случаях), просто не выдает ошибку во время компиляции.

@SneakyThrows
void foo() {
    throw new Exception("bar")'
}
2 голосов
/ 27 июня 2009

Вы можете сделать это с AspectJ. Вы объявляете точку соединения (в данном случае вызов метода foo) и «смягчаете» исключение.

Редактировать Подробнее об этом:

Скажем, у вас есть следующий класс Bar:

public class Bar {

    public void foo() throws Exception {
    }
}

... и у вас есть такой тест:

import junit.framework.TestCase;

public class BarTest extends TestCase {

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

Тогда, очевидно, тест не собирается компилироваться. Это выдаст ошибку:

Unhandled exception type Exception  BarTest.java(line 6)

Теперь, чтобы преодолеть это с AspectJ, вы пишете очень простой аспект:

public aspect SoftenExceptionsInTestCode {

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

    declare soft : Exception : inTestCode();
}

Аспект в основном говорит, что любой код изнутри Test (т. Е. Метод, который начинается с «test» в классе, который заканчивается в «Test» и возвращает «void»), который выдает исключение, должен быть принят AspectJ компилятор. Если возникает исключение, оно будет упаковано и выдано компилятором AspectJ как RuntimeException.

Действительно, если вы запустите этот тест как часть проекта AspectJ из Eclipse (с установленным AJDT), тогда тест будет успешным, тогда как без аспекта он даже не скомпилируется.

1 голос
/ 11 июня 2012

Нет способа сделать это, по крайней мере, сейчас я использую обходной путь, как этот (упрощенный):

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

И использование выглядит так:

import static ....Unchecked.*;

...

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

Хитрость в том, что интерфейс «никогда не завершается», и каждый раз, когда мне нужен где-то непроверенный метод, я помещаю этот объект в непроверенный и позволяю IDE генерировать сигнатуру метода в интерфейсе.

Реализация тогда общая (рефлексивная и "медленная", но обычно достаточно быстрая)

Есть несколько постпроцессоров кода и байт-кодов, но это было невозможно (даже aop или другой язык, основанный на jvm) для моего текущего проекта, так что это было "изобретено".

1 голос
/ 10 мая 2011

Проверенные исключения - это ответственность за реализацию метода. Прими очень, очень внимательно этот факт. если вы не можете использовать подобные обходные артефакты.

1 голос
/ 27 июня 2009

Я думаю, что это возможно с помощью реинжиниринга байт-кода, настраиваемого компилятора или, возможно, аспектно-ориентированного программирования 1 . В отличие от Java, в C # есть только непроверенные исключения 2 .

Могу я спросить, почему вы хотите подавить отмеченные исключения?

1 в соответствии с Maarten Winkels это возможно.
2 и они думают о внедрении проверенных, согласно некоторым видео на 9 канале.

Редактировать: По вопросу: возможно в том смысле, что вы можете аннотировать ваши методы, чтобы пометить их как кандидатов для подавления проверенных исключений. Затем вы используете какой-то трюк времени компиляции или выполнения, чтобы применить фактическое подавление / перенос.

Однако, поскольку я не вижу среды вокруг вашего случая, обертка исключения таким образом может сбить с толку клиентов этого метода - они могут быть не готовы иметь дело с RuntimeException. Например: метод генерирует IOException, и ваши клиенты перехватывают его как FileNotFoundException, чтобы отобразить диалог ошибки. Однако, если вы поместите свое исключение в RuntimeException, диалоговое окно с ошибкой никогда не отобразится и, вероятно, также убьет поток вызывающего. (ИМХО).

0 голосов
/ 07 мая 2014

С Java 8 это так же просто, как: soften(() -> methodThatMayThrow())

Подробнее на http://iirekm.blogspot.com/2014/05/fix-problems-with-java-checked.html

0 голосов
/ 03 мая 2011

Я использую систему завершения / шаблона Eclipse, чтобы легко обернуть любой блок кода.

Вот мой шаблон:

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); 
}
0 голосов
/ 27 июня 2009

Вы можете сделать это в любом случае, используя тот факт, что Class.newInstance не оборачивает Exception, брошенный конструктором no-arg в InvocationTargetException; скорее это бросает это тихо :

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

Тогда вы можете использовать эту утилиту где угодно:

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

Кстати, это действительно плохая идея : -)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...