GWT 请求工厂 +服务定位器错误

发布于 2024-10-29 16:56:40 字数 3023 浏览 2 评论 0原文

我将 GWT 2.2 与 RequestFactory 一起使用。该应用程序有一个现有的服务层(服务器端),因此我使用 ServiceLocator 来提供这些实现。我的 Proxy 和 RequestContexts 指定要使用的正确服务和定位器(如此处< /a>)。我能够对数据发出基本请求,但是当我尝试保存时,出现以下异常:

com.google.gwt.requestfactory.server.UnexpectedException: Could not instantiate Locator com.schedgy.core.service.OrganizationService. Is it default-instantiable?
at com.google.gwt.requestfactory.server.ServiceLayerDecorator.die(ServiceLayerDecorator.java:185)
at com.google.gwt.requestfactory.server.LocatorServiceLayer.newInstance(LocatorServiceLayer.java:222)
at com.google.gwt.requestfactory.server.LocatorServiceLayer.createLocator(LocatorServiceLayer.java:47)
at com.google.gwt.requestfactory.server.ServiceLayerDecorator.createLocator(ServiceLayerDecorator.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

OrganizationService 的定义如下:

// Parent class provides the generic Locator<Organization, String> methods
public class OrganizationService extends CompanyEntityService<Organization> {

        protected OrganizationDao organizationDao;

        protected UserDao userDao;

        protected RoleDao roleDao;

        @Inject
        public OrganizationService(
                OrganizationDao organizationDao,
                UserDao userDao,
                RoleDao roleDao) {

            super(organizationDao, Organization.class);

            this.organizationDao = organizationDao;
            this.userDao = userDao;
            this.roleDao = roleDao;
        }

... additional methods
}

我的定位器类如下所示:

public class CompanyServiceLocator implements ServiceLocator {

    protected Injector injector;

    public CompanyServiceLocator() {        
        injector = GuiceFactory.getInjector();
    }

    @Override
    public Object getInstance(Class<?> clazz) {
        return injector.getInstance(clazz);
    }
}

OrganizationProxy 如下所示:

@ProxyFor(value=Organization.class, locator=OrganizationService.class)
public interface OrganizationProxy extends CompanyEntityProxy {
... setters/getters defined here
}

OrganizationRequest 如下所示:

@Service(value=OrganizationService.class, locator=CompanyServiceLocator.class)
public interface OrganizationRequest extends RequestContext {
...
}

客户端代码如下所示:

OrganizationRequest req = organizationRequestFactory.request();
req.paginate(0, 10).fire(paginationReceiver); // Works!

req = organizationRequestFactory.request();
OrganizationProxy org = req.create(OrganizationProxy.class);
org.setName("test");
req.save(org).fire(receiver); // This causes the server side exception

对我来说,很明显 ServiceLayerDecorator 无法实例化 OrganizationService,因为它没有默认构造函数,但这就是我使用 Guice 并覆盖 ServiceLocator 以使用 Guice 创建服务实例的原因。但为什么第一个调用可以正确使用我的 ServiceLocator,而第二个调用却不能?

I am using GWT 2.2 with RequestFactory. The app has an existing service layer (server side) so I am using a ServiceLocator to provide these implementations. My Proxy and RequestContexts specify the correct service and locator to use (as shown here). I am able to make basic requests for data but when I try to save, I get the following exception:

com.google.gwt.requestfactory.server.UnexpectedException: Could not instantiate Locator com.schedgy.core.service.OrganizationService. Is it default-instantiable?
at com.google.gwt.requestfactory.server.ServiceLayerDecorator.die(ServiceLayerDecorator.java:185)
at com.google.gwt.requestfactory.server.LocatorServiceLayer.newInstance(LocatorServiceLayer.java:222)
at com.google.gwt.requestfactory.server.LocatorServiceLayer.createLocator(LocatorServiceLayer.java:47)
at com.google.gwt.requestfactory.server.ServiceLayerDecorator.createLocator(ServiceLayerDecorator.java:54)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

OrganizationService is defined like:

// Parent class provides the generic Locator<Organization, String> methods
public class OrganizationService extends CompanyEntityService<Organization> {

        protected OrganizationDao organizationDao;

        protected UserDao userDao;

        protected RoleDao roleDao;

        @Inject
        public OrganizationService(
                OrganizationDao organizationDao,
                UserDao userDao,
                RoleDao roleDao) {

            super(organizationDao, Organization.class);

            this.organizationDao = organizationDao;
            this.userDao = userDao;
            this.roleDao = roleDao;
        }

... additional methods
}

My locator class looks like:

public class CompanyServiceLocator implements ServiceLocator {

    protected Injector injector;

    public CompanyServiceLocator() {        
        injector = GuiceFactory.getInjector();
    }

    @Override
    public Object getInstance(Class<?> clazz) {
        return injector.getInstance(clazz);
    }
}

The OrganizationProxy looks like:

@ProxyFor(value=Organization.class, locator=OrganizationService.class)
public interface OrganizationProxy extends CompanyEntityProxy {
... setters/getters defined here
}

The OrganizationRequest looks like:

@Service(value=OrganizationService.class, locator=CompanyServiceLocator.class)
public interface OrganizationRequest extends RequestContext {
...
}

The client side code looks something like:

OrganizationRequest req = organizationRequestFactory.request();
req.paginate(0, 10).fire(paginationReceiver); // Works!

req = organizationRequestFactory.request();
OrganizationProxy org = req.create(OrganizationProxy.class);
org.setName("test");
req.save(org).fire(receiver); // This causes the server side exception

It is obvious to me that ServiceLayerDecorator cannot instantiate OrganizationService because it does not have a default constructor, but this is why I am using Guice and have over-written the ServiceLocator to use Guice to create instances of the service. But why does the first call correctly use my ServiceLocator whereas the second does not?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

隱形的亼 2024-11-05 16:56:40

定位器必须是默认可实例化的。

@ProxyFor(value=Organization.class, locator=OrganizationService.class)

事情正在偏离轨道。如果 OrganizationService 正在出售 Organization 实例来实现 Locator 接口,您需要将其设置为默认可实例化或注入 >ServiceLayerDecorator 实现 createLocator()

第一个代码示例有效而第二个代码示例无效的原因是,第二个代码示例正在根据客户端的命令创建和更改 Organization。在这种情况下,Locator.create() 必须由 RequestFactory 服务器代码调用。在不知道 paginate() 返回给客户端的情况下,我怀疑没有返回 Organization 的实例,因为有必要调用 Locator.getId( )Locator.getVersion() 方法。

Locators must be default-instantiable.

@ProxyFor(value=Organization.class, locator=OrganizationService.class)

is where things are going off the rails. If the OrganizationService is vending instances of Organization to fulfill the Locator interface, you'll need to make it default-instantiable or inject a ServiceLayerDecorator that implements createLocator().

The reason that the first code sample works and not the second is that the second code sample is creating and mutating an Organization based on commands from the client. In this case Locator.create() must be called by the RequestFactory server code. Without knowing what paginate() returns to the client, I suspect that no instances of Organization are being returned since it would be necessary to call the Locator.getId() and Locator.getVersion() methods.

寻梦旅人 2024-11-05 16:56:40

我仍然对为什么两个类需要提供定位器的实现感到困惑,但这是我如何解决这个问题的。

扩展默认的 RequestFactoryServlet,以便您可以默认注入自定义 ServiceLayerDecorator。

public class CompanyRequestFactoryServlet extends RequestFactoryServlet {

    public CompanyRequestFactoryServlet() {
        this(new DefaultExceptionHandler(), new CompanyServiceLayerDecorator());
    }

    public SchedgyRequestFactoryServlet(ExceptionHandler exceptionHandler,
            ServiceLayerDecorator... serviceDecorators) {
        super(exceptionHandler, serviceDecorators);
    }
}

创建一个 ServiceLayerDecorator 来提供 Locator 的实例。我使用 Guice,所以这很简单。下面代码中的 GuiceFactory 只是一个提供 Guice Injector 实例的单例。

public class CompanyServiceLayerDecorator extends ServiceLayerDecorator {

    @Override
    public <T extends Locator<?, ?>> T createLocator(Class<T> clazz) {
        return GuiceFactory.getInjector().getInstance(clazz);
    }
}

最后,更新您的 web.xml 以使用您的自定义 servlet:

<servlet>
    <servlet-name>requestFactoryServlet</servlet-name>
    <servlet-class>com.company.core.requestfactory.CompanyRequestFactoryServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>requestFactoryServlet</servlet-name>
    <url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>

I am still confused on why two classes need to provide implementations for Locators, but here is how I was able to fix this problem.

Extend the default RequestFactoryServlet so that you can inject your custom ServiceLayerDecorator by default.

public class CompanyRequestFactoryServlet extends RequestFactoryServlet {

    public CompanyRequestFactoryServlet() {
        this(new DefaultExceptionHandler(), new CompanyServiceLayerDecorator());
    }

    public SchedgyRequestFactoryServlet(ExceptionHandler exceptionHandler,
            ServiceLayerDecorator... serviceDecorators) {
        super(exceptionHandler, serviceDecorators);
    }
}

Create a ServiceLayerDecorator to provide instances of your Locator's. I use Guice, so this was quite easy. GuiceFactory in the below code is just a singleton that provides an instance of the Guice Injector.

public class CompanyServiceLayerDecorator extends ServiceLayerDecorator {

    @Override
    public <T extends Locator<?, ?>> T createLocator(Class<T> clazz) {
        return GuiceFactory.getInjector().getInstance(clazz);
    }
}

Finally, update your web.xml to use your custom servlet:

<servlet>
    <servlet-name>requestFactoryServlet</servlet-name>
    <servlet-class>com.company.core.requestfactory.CompanyRequestFactoryServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>requestFactoryServlet</servlet-name>
    <url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文