在Java中拯救吞噬的异常 [英] Rescuing a swallowed Exception in Java

查看:181
本文介绍了在Java中拯救吞噬的异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  String getAnswer(){
try {
//做东西,修改实例状态,也许抛出一些异常
// ...
return computeAnswer();
} catch(SomeException e){
return null;
}
}

我想将其更改为: / p>

  String getAnswer()throws SomeException {
//做东西,修改实例状态,可能会抛出一些异常
// ...
return computeAnswer();
}

我不能,因为库已经打包成一个jar。那么有没有办法把异常带回来呢?



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





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

解决方案

您可以在没有反射或AOP的情况下执行此操作。主要思想是在 SomeException 。有一些限制(请参阅这个答案的结尾),但我希望它符合你的需要。



你需要替换 SomeException 使用新版本(只需在原始包中创建一个SomeException.java文件,但在src目录中)具有以下特点:

  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); //< ===关键在这里
}
}

必须取消选中 SomeExceptionWrapperException (继承自RuntimeException或Error)。 catch(...)



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

  //原始的,不可修改的3rdParty代码,这里作为示例
public String getAnswer(){
try {
// some代码
throw new SomeException(a message);
} catch(final SomeException e){
return null;
}
}

//一个包装器getAnswer来解开`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 = getAnswerWra pped();
}

测试将为原始 SomeException ,将被抛出。



限制:



如果以下任一方式,此解决方案将无法正常工作:




  • 如果 SomeException java.lang ,因为您无法替换 java.lang 类(或参见替换java类?

  • 如果第三方方法有一个 catch(Throwable e) / code>(这将是可怕的,应激励你忽略完整的第三方图书馆)


Some 3rd party library swallowed an Exception:

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

As much as I want to change it into:

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

I can't, because the library is already packaged into a jar. So, is there a way to bring the exception back?

I don't need to rethrow, a stacktrace with exception and message would work too.

I don't think reflection would help here, Unsafe perhaps?

Yes I know I can use a debugger to find out what's happening, but that wouldn't be very useful if I need the exception at runtime for logging and stuff like that

解决方案

You can do it without reflection or AOP. The main idea is to throw another (unchecked) exception in the constructor of SomeException. There are some limitations (see at the end of this answer) but I hope it fits your needs.

You need to replace the SomeException with a new version (just create a SomeException.java file in the original package but in your src directory) with something like :

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

The SomeExceptionWrapperException has to be unchecked (inherit from RuntimeException or Error). It will be our wrapper to carry the SomeException accross the ugly 3rd party catch(...)

Then you can catch the SomeExceptionWrapperException in your code (and eventually rethrow the original 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();
}

The test will be green as the original SomeException, will be thrown.

Limitations:

This solution will not work if either :

  • if SomeException is in java.lang as you cannot replace java.lang classes (or see Replacing java class?)
  • if the 3rd party method has a catch(Throwable e) (which will be horrible and should motivate you to ignore the full 3rd party library)

这篇关于在Java中拯救吞噬的异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆