由于 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()
{
// if we get here, reconstructing the original exception did not work
return exceptionClass+": "+super.getMessage();
}
/** Invoked by Serialization to get the real instance */
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)
{
// can't reconstruct exception on client side
}
return this; // use myself as substitute
}
}
现在您可以通过throw new CarryException(originalException);
. 如果类可用,CarryException
它将始终记录原始异常的堆栈跟踪和消息,并在客户端重新创建原始异常。否则,客户端会CarryException
很明显地看到客户端必须知道一种异常类型。
异常类型必须有标准构造函数接收消息String
以使重建工作。(所有其他事情都太复杂了)。但是大多数异常类型都有。
还有另一个Serialization
问题:替换 via 仅在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;
}