在 Java 中拯救吞噬的异常

2022-09-03 15:38:53

一些第三方库吞下了一个例外:

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

尽管我想把它改成:

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

我不能,因为库已经打包成一个罐子。那么,有没有办法让异常恢复呢?

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

我不认为反思在这里会有所帮助,也许?Unsafe

是的,我知道我可以使用调试器来找出发生了什么,但是如果我在运行时需要异常进行日志记录和类似的东西,那将不是很有用。


答案 1

您可以在没有反射或AOP的情况下执行此操作。主要思想是在 的构造函数中引发另一个(未选中的)异常。有一些限制(请参阅本答案的末尾),但我希望它符合您的需求。SomeException

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

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

必须取消选中 (从 RuntimeException 或 Error 继承)。这将是我们的包装,以携带跨越丑陋的第三方SomeExceptionWrapperExceptionSomeExceptioncatch(...)

然后,您可以在代码中捕获 (并最终重新删除原始的 SomeException:SomeExceptionWrapperException

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

测试将是绿色的,因为原始的,将被抛出。SomeException

局限性:

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

  • 如果 是,因为您无法替换类(或参阅替换 java 类?SomeExceptionjava.langjava.lang)
  • 如果第三方方法有一个(这将是可怕的,应该激励你忽略完整的第三方库)catch(Throwable e)

答案 2

为了根据你的约束解决这个问题,我会使用方面(像AspectJ这样的东西)并将其附加到你的异常的创建,记录(或让它调用一些任意的)方法。

http://www.ibm.com/developerworks/library/j-aspectj/


推荐