8

sをスローするセッション Bean を実装していApplicationExceptionます。これらの例外には、クラスがクライアントで使用できない例外が含まれている可能性があるチェーン スタック トレースがあります。何かのようなもの:

@Override
public void doSomethingSpecial(MyObject o) throws MyException {
    try {
        legacySystem.handle(o);
    } catch (LegacyException e) {
        logger.warn(e.getMessage(), e);
        throw new MyException(e);
    }
}

ここで、クライアントがクラスを持たない例外を受け取る可能性があります。これにより、次のことが発生する可能性があります。

Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
    at sun.proxy.$Proxy0.doSomethingSpecial(Unknown Source)
    at com.myapp.client.Client.main(Client.java:56)
Caused by: java.lang.ClassNotFoundException: MyLegacyException

サーバー側でスローされる可能性のあるすべての例外をクライアントに知らせたくはありませんが、スタック トレースを取得することは決して悪いことではありません。

これらの問題をどのように処理しますか? Interceptor例外がクライアントに送り返されたときにスタック トレースを分離する実装はまずまずの解決策ですか? しかし、内部的にはスタック トレース全体に関心があるため、Interceptorは 経由の呼び出しのみを処理する必要があります。RemoteInterface

4

3 に答える 3

0

少し回りくどい解決策を考えましたが、これはテストされていない憶測にすぎません。

外部例外を内部例外で初期化します。しかし、Throwableの javadoc を見ると、get メソッドとsetStackTrace(StackTraceElement[] stackTrace) メソッドが表示されます。

StackTraceElementは文字列で初期化されます。したがって、内部例外からスタック トレースを取得し、それを外部例外 (MyException) に設定することができます。

于 2013-09-20T08:36:17.390 に答える
0

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;
}
于 2013-09-20T08:41:44.263 に答える