通过运行时异常用注释包装异常

发布于 2024-07-25 19:09:20 字数 150 浏览 4 评论 0原文

有没有办法注释一个方法,以便所有抛出的异常都会自动转换为运行时异常?

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

Is there a way to annotate a method so all exceptions thrown are converted to runtime exception automagically?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

谜泪 2024-08-01 19:09:21

Project Lombok 的 @SneakyThrows 可能就是您正在寻找的。 并没有真正包装您的异常(因为在很多情况下它可能是一个问题),它只是在编译期间不会抛出错误。

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

Project Lombok's @SneakyThrows is probably what you are looking for. Is not really wrapping your exception (because it can be a problem in a lot of cases), it just doesn't throw an error during compilation.

@SneakyThrows
void foo() {
    throw new Exception("bar")'
}
躲猫猫 2024-08-01 19:09:21

您可以使用 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”开头的方法) " 并返回 'void') 抛出异常应该被 AspectJ 编译器接受。 如果发生异常,AspectJ 编译器会将其包装并作为 RuntimeException 抛出。

事实上,如果您从 Eclipse(安装了 AJDT)中将这个测试作为 AspectJ 项目的一部分运行,那么测试将会成功,而如果没有该方面,它甚至无法编译。

You can do this with AspectJ. You declare a joinpoint (in this case invocation of the method foo) and 'soften' the exception.

Edit To elaborate a bit on this:

Say you have the following class Bar:

public class Bar {

    public void foo() throws Exception {
    }
}

...and you have a test like this:

import junit.framework.TestCase;

public class BarTest extends TestCase {

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

Then obviously the test is not going to compile. It will give an error:

Unhandled exception type Exception  BarTest.java(line 6)

Now to overcome this with AspectJ, you write a very simple aspect:

public aspect SoftenExceptionsInTestCode {

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

    declare soft : Exception : inTestCode();
}

The aspect basically says that any code from within a Test (i.e.: a method that starts with "test" in a class that ends in "Test" and returns 'void') that throws an exception should be accepted by the AspectJ compiler. If an exception occurs, it will be wrapped and thrown as a RuntimeException by the AspectJ compiler.

Indeed, if you run this test as part of an AspectJ project from within Eclipse (with AJDT installed) then the test will succeed, whereas without the aspect it won't even compile.

吾家有女初长成 2024-08-01 19:09:21

没办法做到这一点,至少现在我使用这样的解决方法(简化):

@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的语言),所以这是“发明”。

No way to do that, at least for now I use workaround like this (simplified):

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

And the usage looks like:

import static ....Unchecked.*;

...

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

The trick is that interface is "never finished" and everytime I need unchecked method somewhere, I'll wrap that object into unchecked and let IDE generate method signature in interface.

Implementation is then generic (reflective and "slow" but usually fast enough)

There are some code post-processors and bytecode-weavers but this was not possible (not even aop or other jvm based language) for my current project, so this was "invented".

凹づ凸ル 2024-08-01 19:09:21

我认为通过字节码重新设计、定制编译器或者面向方面的编程1是可能的。 与 Java 不同,C# 仅有未经检查的异常2

请问为什么要抑制已检查的异常?

1 根据 Maarten Winkels 的说法,这是可能的。
2 根据第 9 频道的一些视频,他们正在考虑引入经过检查的产品。

编辑:对于这个问题:从某种意义上说,您可以注释您的方法以将它们标记为检查异常抑制的候选者。 然后,您使用一些编译时或运行时技巧来应用实际的抑制/包装。

但是,由于我没有看到您的情况周围的环境,因此以这些方式包装异常可能会使该方法的客户端感到困惑 - 他们可能不准备处理 RuntimeException。 例如:该方法抛出 IOException,并且您的客户端将其捕获为 FileNotFoundException 以显示错误对话框。 但是,如果将异常包装到 RuntimeException 中,则错误对话框永远不会显示,并且可能还会杀死调用者线程。 (恕我直言)。

I think it is possible with bytecode re-engineering, customized compiler or perhaps aspect oriented programming1. In the contrary to Java, C# has only unchecked exceptions2.

May I ask why you want to suppress the checked exceptions?

1 according to Maarten Winkels this is possible.
2 and they are thinking about introducing checked ones, according to some Channel 9 videos.

Edit: For the question: It is possible in the sense that you can annotate your methods to flag them to be a candidate for checked exception suppression. Then you use some compile time or runtime trick to apply the actual suppression / wrapping.

However, as I don't see the environment around your case, wrapping an exception in these ways might confuse the clients of that method - they might not be prepared to deal with a RuntimeException. For example: the method throws an IOException and your clients catches it as FileNotFoundException to display an error dialog. However if you wrap your exception into a RuntimeException, the error dialog gets never shown and probably it kills the caller thread too. (IMHO).

太阳公公是暖光 2024-08-01 19:09:21

检查的异常是方法实现的责任。
非常非常仔细地对待这个事实。 如果可以的话,不要使用类似的解决方法工件。

The Checked exceptions are responsability of the method implementation.
Take very very carefully this fact. if you can do not use workaround artifacts like that.

倒带 2024-08-01 19:09:21

在任何情况下,您都可以通过以下事实来做到这一点:Class.newInstance 不会将无参数构造函数抛出的 Exception 包装在InvokingTargetException; 相反,它默默地抛出它

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

顺便说一句,这是一个非常糟糕的主意:-)

You can do this in any case via use of the fact that Class.newInstance does not wrap an Exception thrown by the no-arg constructor in an InvocationTargetException; rather it throws it silently:

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

Then you can use this utility anywhere:

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

By the way, this is a really bad idea :-)

鹤舞 2024-08-01 19:09:21

我使用 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); 
}

I use the completion / template system of Eclipse to wrap any block of code easily.

Here is my template :

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); 
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文