GWT RF: How to share the same code in client and server

社会主义新天地 提交于 2019-12-06 10:46:23
Manolo Carrasco Moñino

As Thomas says in his answer, the only way in current GWT to have shared code in client and sever is implementing the same interface in both sides and using it in your shared code.

Since RF copies attributes from the server to the client as you say in your query, in theory we could use the same interface (the proxy one) in both sides (simpler code), setting the @ValueFor value pointing to itself.

Lets see an example:

 // Shared interface in client and server sides
 @ProxyFor(Foo.class)
 interface Foo extends ValueProxy {
    String getBar();
 }

 // Server side implementation
 class FooImpl implements Foo {
    String getBar(){return "bar";};
 }

As information, we use this approach in our product, so as we can sell 2 backend solutions (one is based on GAE and other on couchdb).

The code above works for client code which does not create new values, but if you want to create them, it is enough to define a value locator:

 // Say RF which locator to use to create classes in server side
 @ProxyFor(value = Foo.class, locator ALocator.class)
 interface Foo extends ValueProxy {
 }

 public class ALocator extends Locator<Foo, String>  {
   public Foo create(Class<? extends Foo> clazz) {
    return new FooImpl();
   }
   ...
 }

Unfortunately, RF does not deal with interfaces in the server side see issues: 7509 and 5762.

But, as you can read in the issues comments, there is already a fix for this (pending for review). Hopefully it would be included in a next release of GWT.

In the meanwhile, you can use this approach, just copying the file ResolverServiceLayer.java in your src folder and applying this patch to it.

One way to use the same API is to use interfaces that both your proxies extend and your domain objects implement.

// common interfaces
interface Foo { … }
interface Bar<T extends Foo> {
  int getX();
  void setX(int x);

  // setters need to use generics
  List<T> getFoos();
  void setFoos(List<T> foos);

  // with only a getter, things get easier:
  Bar getParent();
}

// domain objects
class RealFoo implements Foo { … }
class RealBar implements Bar<RealFoo> {
  int x;
  List<RealFoo> foos;
  RealBar parent;

  @Override
  public RealBar getParent() { return parent; }

  // other getters and setters
}

// proxy interfaces
@ProxyFor(RealFoo.class)
interface FooProxy extends Foo { … }

@ProxyFor(RealBar.class)
interface BarProxy extends Bar<FooProxy> {
  @Override
  BarProxy getParent();

  // other getters and setters
}

You can then use a Comparator<Foo> or Comparator<Bar> in both client and server side.

I generally only implement traits (aspects, facets, call them the way you like) that way though (HasId, HasLabel, HasPosition, etc.), not complete domain objects' APIs. I can then use HasId to get the key of any object to put them in a map or compare for equality, HasLabel for displays (custom Cells on the client-side, error messages on the server-side that are sent to the client, etc.), HasPosition for sorting, etc.

The point of RequestFactory is that it does not do use the same type. Each request context describes a set of operations to perform when the call gets to the server (create and find things, then apply setters, then run service methods). As calls are described as just proxies to the real thing on the server, you need a 'fake' model object like a EntityProxy or ValueProxy to ensure that the only calls that can be made are getters and setters - and that sometimes, setters are not allows (when an object has been read from the server but before it has been edited).

If your models are simple, i.e. not holding other objects, but only string, date, and primitives, you can have both the entity and the proxy implement the same interface. However, if the model holds sub-objects, then this is more difficult - the only way possible is to leave out those getters and setters. Otherwise, you can't override those methods in the proxy type to specify the proxy version of that nested object.

Consider using RPC isntead if you actually want to reuse the same types on the client and server.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!