【问题标题】:RequestFactory fails with "UnexpectedException: No RequestContext for operation LPZEK7DlYkoG1$NQ5MjHlmuRChk="RequestFactory 失败,出现“UnexpectedException: No RequestContext for operation LPZEK7DlYkoG1$NQ5MjHlmuRChk="
【发布时间】:2023-03-25 01:03:01
【问题描述】:

你们能帮我解释一下为什么会出现这个异常吗?

我将 RequestFactory 代理和上下文接口提取到单独的 jar 中,这样我就可以在 GWT 客户端和 Android 客户端中使用它(详细信息是 here

不幸的是,RF 在第一次调用时就在服务器上引发了异常。例外是:

com.google.web.bindery.requestfactory.server.UnexpectedException: No RequestContext for operation LPZEK7DlYkoG1$NQ5MjHlmuRChk=
    at com.google.web.bindery.requestfactory.server.ServiceLayerDecorator.die(ServiceLayerDecorator.java:216)
    at com.google.web.bindery.requestfactory.server.ResolverServiceLayer.resolveRequestContext(ResolverServiceLayer.java:154)

下面是我的工厂界面。如您所见,我不得不将 Service 注释替换为 ServiceName,因为我不想将所有带有 Guice 注入的自定义定位器编译为将在移动设备上运行的 jar。

public interface AdminRequestFactory extends RequestFactory
{
    // @Service(value = UserServiceDao.class, locator = InjectingServiceLocator.class)
    @ServiceName(value = "com.blah.courierApp.server.dao.UserServiceDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
    public interface GaeUserServiceContext extends RequestContext
    {
        public Request<String> createLogoutURL(String destinationURL);
        public Request<GaeUser> getCurrentUser();
    }

    // @Service(value = OrderDao.class, locator = InjectingServiceLocator.class)
    @ServiceName(value = "com.blah.courierApp.server.dao.OrderDao", locator = "com.blah.courierApp.server.inject.InjectingServiceLocator")
    public interface OrderRequestContext extends RequestContext
    {
        Request<List<OrderProxy>> listAll();
        Request<Void> delete(Long id);
        Request<Void> createOrder(OrderProxy order);
        Request<OrderProxy> findOrderById(long id);
        Request<Void> updateOrderState(long id, StateType newStateType);
    }

    GaeUserServiceContext contextUserService();
    OrderRequestContext contextOrder();
}

当我编译它时,RF Annotation Tool 给出了以下警告:

Cannot fully validate context since domain type com.blah.courierApp.server.dao.UserServiceDao is not available.
You must run the ValidationTool as part of your server build process.
Add @SuppressWarnings("requestfactory") to dismiss.

因此,当服务器上的调试器下抛出异常时,我看到 com.google.web.bindery.requestfactory.vm.impl.Deobfuscator 的实例有空的 operationData 字段,该字段正在由 RequestFactory 注释工具生成的 DeobfuscatorBuilder 类初始化。

所以...我反编译了那个类,发现了这个:

public final class AdminRequestFactoryDeobfuscatorBuilder extends Deobfuscator.Builder
{
  public AdminRequestFactoryDeobfuscatorBuilder()
  {
    withRawTypeToken("w1Qg$YHpDaNcHrR5HZ$23y518nA=", "com.google.web.bindery.requestfactory.shared.EntityProxy");
    withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
    withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
    withRawTypeToken("5vjE9LUy$l0uvi4kMYpS3JA1WEE=", "com.blah.shared.model.GaeUser");
    withRawTypeToken("8KVVbwaaAtl6KgQNlOTsLCp9TIU=", "com.google.web.bindery.requestfactory.shared.ValueProxy");
    withRawTypeToken("5a7OV4PSV$1xemsooKLfEQ4g5yY=", "com.blah.shared.proxies.OrderProxy");
    withRawTypeToken("neR_xIhE5oZsc0HbnkAMa8A88yw=", "com.blah.shared.proxies.OrderStateProxy");
    withRawTypeToken("t6gMQWDROJnYvqYhNURV8pd$sn4=", "com.blah.shared.proxies.OrganizationProxy");
    withRawTypeToken("1o45xgS$5bIkBKF4wlR8oMw_FSo=", "com.blah.shared.proxies.PersonProxy");
    withRawTypeToken("FXHD5YU0TiUl3uBaepdkYaowx9k=", "com.google.web.bindery.requestfactory.shared.BaseProxy");
  }
}

它没有为工厂生成令牌。因此,没有对 Deobfuscator.Builder.withOperation 的调用,因此当调用来自客户端时,我的服务器无法找到上下文。

问题是:

  • 为什么 RequestFactory 注释工具不为工厂(操作)生成令牌?
  • 我该如何解决?

【问题讨论】:

    标签: android gwt annotations gwt2 requestfactory


    【解决方案1】:

    嗯,这很棘手...但是在 RF 注释工具中进行调试很有帮助:)

    原来您必须在 RF 注释处理器的类路径中拥有您在 @ServiceName 中引用的域类。它创造了先有鸡还是先有蛋的问题。您必须编译SharedClasses 模块才能编译主模块,但您必须从主模块编译域类才能编译SharedClasses 模块。

    这是我所做的:

    • 为 SharedClasses 模块禁用 RF 注释处理。
    • 在射频注释处理器主模块中,我明确指定了必须使用参数rootOverride = com.blah.shared.factories.AdminRequestFactory处理的射频工厂

    不过,我在项目设置中硬编码了完整的合格类名,这很糟糕。

    如果你们知道更优雅的方法,请告诉我。

    【讨论】:

      【解决方案2】:

      我也遇到了同样的问题。基本上我有 3 个 GWT 模块 1. 主模块,在第二个模块中我有 requestFactory、服务器域类和客户端代理值。我非常确定您的解决方案是我需要实施的。但是我很困惑如何在 Maven 构建阶段指定 rootOverride。 pom.xml 结构中的任何指针都会非常有帮助。

      【讨论】:

      • 我建议删除这篇文章,因为它显然不是一个答案(不过你可以将它作为答案发布)。