由于RMI使用Serialization
,您可以使用Serialization
功能有条件地替换异常。
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
public class CarryException extends RuntimeException implements Serializable
{
final String exceptionClass;
public CarryException(Exception cause)
{
super(cause.getMessage());
exceptionClass=cause.getClass().getName();
setStackTrace(cause.getStackTrace());
}
@Override
public String getMessage()
{
return exceptionClass+": "+super.getMessage();
}
final Object readResolve() throws ObjectStreamException
{
try
{
Exception ex = Class.forName(exceptionClass).asSubclass(Exception.class)
.getConstructor(String.class).newInstance(super.getMessage());
ex.setStackTrace(getStackTrace());
return ex;
}
catch(InstantiationException|IllegalAccessException|ClassNotFoundException
| IllegalArgumentException|InvocationTargetException|NoSuchMethodException
| SecurityException ex)
{
}
return this;
}
}
现在你可以通过
throw new CarryException(originalException);
向客户端抛出任何异常。
CarryException
将始终记录原始异常的堆栈跟踪和消息,并在客户端重建原始异常(如果类可用)。否则,客户端将看到
CarryException
,因此一个异常类型必须在客户端上已知。
异常类型必须具有标准构造函数,以便重建工作,该构造函数需要一个消息
String
。(其他所有事情都太复杂了)。但是大多数异常类型都有这个构造函数。
还有一个问题:仅通过
Serialization
替换只有在涉及
Serialization
时才起作用,因此当在同一JVM内部时不要直接调用实现类上的方法。否则,您无条件地看到
CarryException
。因此,即使在本地,您也必须使用存根,例如。
((MyRemoteInterface)RemoteObject.toStub(myImplementation)).doSomethingSpecial()
更新
如果客户端已知道MyException
,并且只有LegacyException
未知,那么以下代码当然可以正常工作:
catch (LegacyException e) {
logger.warn(e.getMessage(), e);
MyException me=new MyException(e.toString());
me.setStackTrace(e.getStackTrace());
throw me;
}