将泛型与 GWT-RPC 一起使用未按预期工作

Posted

技术标签:

【中文标题】将泛型与 GWT-RPC 一起使用未按预期工作【英文标题】:Using Generics with GWT-RPC isn't working as expected 【发布时间】:2014-02-10 20:13:03 【问题描述】:

我没有创建一百个不同的 GWT-RPC 服务和 serviceAsync 类,而是尝试使用泛型创建一个服务。界面如下:

@RemoteServiceRelativePath("dispatch")
public interface CommandService extends RemoteService

    public <T> Result<T> execute(Command command, T target);

这里Command 是我可以发出的所有不同命令的枚举,例如Login, Register, ChangePassword'等。在服务器端,我有一个CommandHashMap 作为键,并且Executor 类作为值。对于每个Command,我都有一个对应的Executor。那个Executor被执行了,它的返回值在服务器端返回。

当我尝试在客户端上创建CommandServiceAsync 并尝试执行它时,就会出现问题。这是我的代码:

public enum Command

    LOGIN,
    REGISTER,
    CHANGE_PW;

    public <T> void execute(T target, final ResultReceiver<T> receiver)
    
        CommandServiceAsync command = GWT.create(CommandService.class );
        command.execute(this, target, new AsyncCallback<Result<T> >()
        
            @Override
            public void onFailure(Throwable caught)
            
                MyProgram.handleFailure(caught);
            

            @Override
            public void onSuccess(Result<T> result)
            
                receiver.receive( result );;
            
        );
    

这里,Command.execute 是实际调用服务的方法。下面是我如何调用它来执行LOGIN 命令:

LoginForm form = new LoginForm();
Command.LOGIN.execute(form, new ResultReceiver<LoginForm>()

    @Override
    public void receive(Result<LoginForm> result)
    
        Console.debug("Received result");
        //result.getTarget() will return an instance of LoginForm
        Console.debug("user: " + result.getTarget().getUser() );
        Console.debug("pw: " + result.getTarget().getUser() );
    
);

问题出现在Command.execute 中的以下行:

CommandServiceAsync command = GWT.create(CommandService.class );

在这里,我收到以下错误:

错误:“com.xxx.CommandService”的延迟绑定失败;预计 随后的失败

错误:未捕获的异常已转义 com.google.gwt.event.shared.UmbrellaException:捕获异常: 'com.xxx.CommandService' 的延迟绑定失败(你忘了 继承一个必需的模块?)

原因: com.google.gwt.core.ext.UnableToCompleteException:(见上一个日志 条目)

我怎样才能完成我想做的事情?

【问题讨论】:

【参考方案1】:

在客户端 GWT 应用程序中,所有类型都必须在编译时已知。拥有像您描述的那样的通用方法根本行不通。

你可以试试下面的方法

public interface CommandService extends RemoteService 
    public Result<Serializable> execute(Command command, Serializable target);

您将失去一些类型安全性并受到一些限制,但这应该可行。

Request Factory 可能更适合这种情况。它对服务器端代码在哪里进行实际工作提供了很多宽大处理。

GWT 源代码中有一个 Request Factory 示例项目。 gwtproject.org 网站上有关于获取源代码的非常清晰的说明,here。查看eclipse 目录中的README 文件。这将帮助您入门。

编辑:

正如@ColinAlworth 所指出的,在 RPC 方法中使用简单接口时应该非常小心。上面的方法告诉编译器它应该能够通过它可以访问的线路发送每个可序列化对象,并且将为每个单独的对象创建序列化器和反序列化器!

【讨论】:

对此要非常小心——你明确告诉编译器它可以通过网络发送any可序列化对象。 RPC 生成器将挑选出 GWT 有权访问的任何 Serializable,并为其构建序列化器和反序列化器并编译类型,即使您从未在项目的其他地方使用这些类型。 感谢@ColinAlworth【参考方案2】:

对 GWT-RPC 使用泛型和对象类是一种不好的方法。有时它会抛出一个序列化异常,有时它不会,但它不会工作。这样做的原因是,GWT 在编译时创建白名单或序列化策略。为此,您需要知道您正在使用的确切类。 更多详情,请查看以下链接

Serialization Exception while making an RPC call

【讨论】:

那么在 GWT 中使用命令模式的最佳方式是什么? 命令模式是推荐用于gwt编程的设计模式之一。如果你观察,甚至 AsyncCallback 就是一个例子。但是对于 gwt -rpc 你不能使用涉及泛型的命令模式。它必须是实现 Serializable 或 IsSeralizable 的具体类 我明白了。但我不明白在这种情况下如何将命令模式用于缓存 gwt 请求之类的事情。我看过一个关于它的视频,他在那里制作了一个动作和Response 界面。然后他创建了一个以 作为参数的 ContactService GWT 接口,并返回一个 。但我不明白为什么在这种情况下甚至需要使用ActionResponse。以及如何使用它来实现缓存?有什么想法吗? 使用T extends Action 告诉编译器只有Action 子类可以通过网络发送,这大大减少了它需要生成的序列化代码(最终会出现在你的JS代码中)。请参阅@Jonathan 的回答。

以上是关于将泛型与 GWT-RPC 一起使用未按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

将泛型与可能是值或引用类型的 null 进行比较?

Mailchimp mc:repeatable & mc:variant 未按预期工作

Mongoose pre.save() 异步中间件未按预期工作

Mongoose pre.save() 异步中间件未按预期工作

用于鼠标位置的 Python Kalman 滤波器未按预期工作

Oauth2 安全配置匹配器请求过滤未按预期工作