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
ないと、クライアント側で 1 つの例外タイプを認識しなければならないことは明らかです。
例外タイプString
には、再構築が機能するためにメッセージを受け取る標準コンストラクターが必要です。(他のすべてのことは複雑すぎるでしょう)。しかし、ほとんどの例外タイプにはそれがあります。
もう 1 つの問題があります。via の置換は が関係して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;
}