在Java中拯救吞噬的异常

tom*_*136 15 java exception-handling exception

一些第三方图书馆吞下了一个例外:

String getAnswer(){
    try{
        // do stuff, modify instance state, maybe throw some exceptions
        // ...
        return computeAnswer(); 
    }catch (SomeException e){
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想把它改成:

String getAnswer() throws SomeException{
    // do stuff, modify instance state, maybe throw some exceptions
    // ...
    return computeAnswer();
}
Run Code Online (Sandbox Code Playgroud)

我不能,因为库已经打包成一个罐子.那么,有没有办法将异常带回来?

我不需要重新抛出,带有异常的堆栈跟踪和消息也可以工作.

我不认为这里的反思会有所帮助Unsafe吗?

是的我知道我可以使用调试器来查明发生了什么,但是如果我在运行时需要异常以进行日志记录和那样的事情,这将不会非常有用

Ben*_*oît 4

您无需反射或 AOP 即可完成此操作。主要思想是在 的构造函数中抛出另一个(未经检查的)异常SomeException。有一些限制(请参阅本答案的末尾),但我希望它适合您的需求。

您需要将其替换SomeException为新版本(只需在原始包中但在 src 目录中创建一个 SomeException.java 文件),如下所示:

package com.3rdpartylibrary;

public class SomeException extends Exception {
    public static class SomeExceptionWrapperException extends RuntimeException {
        public SomeExceptionWrapperException(final SomeException ex) {
            super(ex.getMessage(), ex);
        }
    }

    public SomeException(final String message) {
        super(message);
        throw new SomeExceptionWrapperException(this); //<=== the key is here
    }
}
Run Code Online (Sandbox Code Playgroud)

必须SomeExceptionWrapperException取消选中(继承自 RuntimeException 或 Error)。这将是我们的包装纸,用来携带SomeException穿过丑陋的第三者catch(...)

SomeExceptionWrapperException然后你可以在代码中捕获(并最终重新抛出原始的 SomeException:

//original, unmodifiable 3rdParty code, here as a example
public String getAnswer() {
    try {
        //some code
        throw new SomeException("a message");
    } catch (final SomeException e) {
        return null;
    }
}

//a wrapper to getAnswer to unwrapp the `SomeException`
public String getAnswerWrapped() throws SomeException {
    try {
        return getAnswer();
    } catch (final SomeExceptionWrapperException e) {
        throw (SomeException) e.getCause();
    }
}

@Test(expected = SomeException.class)
public void testThrow() throws SomeException {
    final String t = getAnswerWrapped();
}
Run Code Online (Sandbox Code Playgroud)

测试将像原始测试一样呈绿色SomeException,并将被抛出。

限制:

如果出现以下情况,此解决方案将不起作用:

  • ifSomeExceptionjava.lang因为你不能替换java.lang类(或者参见替换 java 类?
  • 如果第 3 方方法有catch(Throwable e)(这将是可怕的,并且应该促使您忽略完整的第 3 方库)