拦截GWT RPC的异步代理服务异常

时间:2013-01-14 19:47:25

标签: gwt exception-handling gwt-rpc

我的应用程序有很多RPC调用,并且它们都有.onFailure(Throwable caught)方法。我在客户端和服务器代码NotLoggedInException之间共享一个类。如果用户没有基于会话/ cookie /权限等的相关权限,则由服务器抛出。

理想情况下,我想在其他地方传递给.onFailure()代码之前在一个地方处理此异常,因为这种处理无处不在并且需要安全性。有一个GWT.setUncaughtExceptionHandler(),但这似乎是在处理之后调用的,这是不理想的(如果.onFailure意外消耗太多)。

有人有一个优雅的解决方案吗?一个丑陋的解决方案是将延迟绑定的.create()代理包装在实现异步接口的同一聚合类中。

旁注:服务器之前正在发布重定向,但我不喜欢这种模式,并希望它由应用程序的事件总线处理。

更新:上面提到的丑陋答案

public abstract class CustomAsyncCallback implements AsyncCallback{

@Override
public CustomAsyncCallback(AsyncCallback<T> callback)
{
    this.wrap = callback ;
}

AsyncCallback<T> wrap ;


@Override
public void onFailure(Throwable caught) {
    if (!handleException())
{
    wrap.onFailure(caught) ;
}
}

@Override
public void onSuccess(T t) {
    wrap.onSuccess(t) ;
}

}

public class WrapDeferredBinding implements RpcInterfaceAsync { RpcInterfaceAsync service = GWT.create(RpcInterface.class);

public void method1(int arg1, AsyncCallback<Boolean> callback)
{
    service.method1(arg1, new CustomAsyncCallback<Boolean>(callback)) ;
}

public void method2 ....
public void method3 ....

@Override public CustomAsyncCallback(AsyncCallback<T> callback) { this.wrap = callback ; } AsyncCallback<T> wrap ; @Override public void onFailure(Throwable caught) { if (!handleException()) { wrap.onFailure(caught) ; } } @Override public void onSuccess(T t) { wrap.onSuccess(t) ; }

2 个答案:

答案 0 :(得分:8)

为了包装传递给任何AsynCallback<T>的每个RemoteService,您需要覆盖RemoteServiceProxy#doCreateRequestCallback(),因为在发生RPC调用之前,每个AsynCallback<T>都会被传递。< / p>

以下是执行此操作的步骤:

首先,您需要定义自己的代理生成器,以便在每次生成RemoteService代理时进入。首先展开ServiceInterfaceProxyGenerator并覆盖#createProxyCreator()

/**
 * This Generator extends the default GWT {@link ServiceInterfaceProxyGenerator} and replaces it in the
 * co.company.MyModule GWT module for all types that are assignable to
 * {@link com.google.gwt.user.client.rpc.RemoteService}. Instead of the default GWT {@link ProxyCreator} it provides the
 * {@link MyProxyCreator}.
 */
public class MyServiceInterfaceProxyGenerator extends ServiceInterfaceProxyGenerator {
    @Override
    protected ProxyCreator createProxyCreator(JClassType remoteService) {
        return new MyProxyCreator(remoteService);
    }
}

MyModule.gwt.xml中使用延迟绑定来指示GWT在生成RemoteService类型的内容时使用您的代理生成器进行编译:

<generate-with 
   class="com.company.ourapp.rebind.rpc.MyServiceInterfaceProxyGenerator">
    <when-type-assignable class="com.google.gwt.user.client.rpc.RemoteService"/>
</generate-with>

扩展ProxyCreator并覆盖#getProxySupertype()。在MyServiceInterfaceProxyGenerator#createProxyCreator()中使用它,以便您可以为所有生成的RemoteServiceProxies定义基类。

/**
 * This proxy creator extends the default GWT {@link ProxyCreator} and replaces {@link RemoteServiceProxy} as base class
 * of proxies with {@link MyRemoteServiceProxy}.
 */
public class MyProxyCreator extends ProxyCreator {
    public MyProxyCreator(JClassType serviceIntf) {
        super(serviceIntf);
    }

    @Override
    protected Class<? extends RemoteServiceProxy> getProxySupertype() {
        return MyRemoteServiceProxy.class;
    }
}

确保您的MyProxyCreatorMyServiceInterfaceProxyGenerator位于不会被GWT交叉编译为javascript的程序包中。否则你会看到如下错误:

[ERROR] Line XX: No source code is available for type com.google.gwt.user.rebind.rpc.ProxyCreator; did you forget to inherit a required module?

您现在可以扩展RemoteServiceProxy并覆盖#doCreateRequestCallback()了!在这里,您可以执行任何您喜欢的操作,并将其应用于发送到服务器的每个回调。确保将此类以及您在此处使用的任何其他类(在我的案例AsyncCallbackProxy中)添加到您的客户端包中以进行交叉编译。

/**
 * The remote service proxy extends default GWT {@link RemoteServiceProxy} and proxies the {@link AsyncCallback} with
 * the {@link AsyncCallbackProxy}.
 */
public class MyRemoteServiceProxy extends RemoteServiceProxy {
    public MyRemoteServiceProxy(String moduleBaseURL, String remoteServiceRelativePath, String serializationPolicyName,
                                 Serializer serializer) {
        super(moduleBaseURL, remoteServiceRelativePath, serializationPolicyName, serializer);
    }

    @Override
    protected <T> RequestCallback doCreateRequestCallback(RequestCallbackAdapter.ResponseReader responseReader,
                                                          String methodName, RpcStatsContext statsContext,
                                                          AsyncCallback<T> callback) {
        return super.doCreateRequestCallback(responseReader, methodName, statsContext, new AsyncCallbackProxy<T>(callback));
    }
}

现在,您的AsyncCallbackProxy看起来像这样:

public class AsyncCallbackProxy<T> implements AsyncCallback<T> {
    private AsyncCallback<T> delegate;

    public AsyncCallbackProxy(AsyncCallback<T> delegate) {
        this.delegate = delegate;
    }

    @Override
    public final void onFailure(Throwable caught) {
        GWT.log("AsyncCallbackProxy#onFailure() : " + caught.getMessage(), caught);

        if (caught instanceof NotLoggedInException) {
            // Handle it here
        }

        delegate.onFailure(proxy);
    }

    @Override
    public final void onSuccess(T result) {
        delegate.onSuccess(result);
    }
}

参考文献:

答案 1 :(得分:1)

您可以使用抽象类包装AsyncCallback类:

public abstract class CustomAsyncCallback<T> implements AsyncCallback<T>{

    @Override
    public void onFailure(Throwable caught) {
        GWT.log(caught.getMessage());
        handleException();

        this.customOnFailure(yourDesireParam);
    }

    /**
     * this method is optional
     */
    public abstract void customOnFailure(Param yourDesireParam);
}

然后将CustomAsyncCallback对象发送到RPC异步方法。