GWT RF: как использовать один и тот же код на клиенте и сервере

Я хотел бы использовать один и тот же код для сортировки и управления объектами на стороне клиента и сервера.

Но я столкнулся с проблемой, так как в клиенте нам нужен прокси-интерфейс, представляющий класс сервера.

Есть ли способ использовать один и тот же интерфейс в обоих? Я знаю, что RF имеет механизм для копирования атрибутов bean-компонента из экземпляра сервера в экземпляр клиента, когда он отправляется по сети.


person Community    schedule 06.04.2013    source источник
comment
Вы знаете об общем пакете?   -  person Suresh Atta    schedule 06.04.2013
comment
Да, я знаю, мой вопрос в том, почему я должен использовать прокси-интерфейс (ItemProxy.java) на клиенте и реализацию (Item.java) на сервере вместо использования одного и того же интерфейса в обоих.   -  person    schedule 06.04.2013
comment
Интерфейс EntityProxy позволяет RequestFactory вычислять и отправлять на сервер только изменения (дельты).   -  person Suresh Atta    schedule 06.04.2013
comment
да, я использую ValueProxy, хотя я не использую стандартную модель постоянства в своем бэкэнде.   -  person    schedule 06.04.2013


Ответы (3)


Как говорит Томас в своем ответе единственный способ в текущем GWT иметь общий код на клиенте и сервере — реализовать один и тот же интерфейс на обеих сторонах и использовать его в вашем общем коде.

Поскольку RF копирует атрибуты с сервера на клиент, как вы говорите в своем запросе, теоретически мы могли бы использовать один и тот же интерфейс (прокси) с обеих сторон (более простой код), установив значение @ValueFor, указывающее на себя.

Давайте посмотрим пример:

 // 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";};
 }

В качестве информации, мы используем этот подход в нашем продукте, так как мы можем продавать 2 серверных решения (одно основано на GAE, а другое на CouchDB).

Приведенный выше код работает для клиентского кода, который не создает новые значения, но если вы хотите их создать, достаточно определить локатор значений:

 // 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();
   }
   ...
 }

К сожалению, RF не работает с интерфейсами на стороне сервера. См. проблемы: 7509 и 5762.

Но, как вы можете прочитать в комментариях к проблемам, для это (ожидает рассмотрения). Надеюсь, он будет включен в следующий выпуск GWT.

А пока вы можете использовать этот подход, просто скопировав файл ResolverServiceLayer.java в свою папку src и применив этот исправление для него.

person Manolo Carrasco Moñino    schedule 06.04.2013
comment
Спасибо, Маноло, я пропатчил файл, и он работает!. Сообщите мне, когда выйдет патч. - person ; 07.04.2013

Одним из способов использования одного и того же API является использование интерфейсов, которые расширяют как ваши прокси-серверы, так и объекты вашего домена.

// 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
}

Затем вы можете использовать Comparator<Foo> или Comparator<Bar> как на стороне клиента, так и на стороне сервера.

Обычно я реализую черты (аспекты, фасеты, называйте их как хотите) таким образом, хотя (HasId, HasLabel, HasPosition и т. д. ), а не полные API-интерфейсы доменных объектов. Затем я могу использовать HasId, чтобы получить ключ любого объекта, чтобы поместить их на карту или сравнить на равенство, HasLabel для отображения (настраиваемые Cell на стороне клиента, сообщения об ошибках на стороне сервера, которые отправляются клиенту и т. д. .), HasPosition для сортировки и т. д.

person Thomas Broyer    schedule 06.04.2013
comment
Спасибо, Томас, я проверю этот подход. - person ; 07.04.2013
comment
Работает как часы. Я выбрал другой ответ, потому что он проще. - person ; 07.04.2013
comment
Томас, мы начали использовать тот же подход общих интерфейсов для повторного использования кода между клиентом и сервером. Но у нас возникла очень странная проблема. Все работает как шарм в режиме GWT super dev. Но когда мы делаем полную компиляцию и развертывание, мы получаем исключение: java.lang.UnsupportedOperationException: IAppointment. Исключение выдается из кода: EntityCodex#decode() --> ValueCodex#decode(). Один и тот же параметр метода type из EntityCodex#decode() из разрешается как AppointmentProxy в режиме суперразработчика, но как IAppointment в полностью скомпилированном приложении. Мы используем GWT 2.6.1 и Java 8. - person ilya; 19.04.2016

Смысл RequestFactory в том, что он не использует один и тот же тип. Каждый контекст запроса описывает набор операций, которые необходимо выполнить, когда вызов поступает на сервер (создание и поиск вещей, затем применение сеттеров, затем запуск методов службы). Поскольку вызовы описываются как прокси-серверы для реальных вещей на сервере, вам нужен «фальшивый» объект модели, такой как EntityProxy или ValueProxy, чтобы гарантировать, что единственными возможными вызовами являются геттеры и сеттеры, а иногда и сеттеры не являются разрешает (когда объект был прочитан с сервера, но до его редактирования).

Если ваши модели просты, т. е. не содержат других объектов, а содержат только строку, дату и примитивы, вы можете иметь и сущность, и прокси-сервер, реализующие один и тот же интерфейс. Однако, если модель содержит подобъекты, то это сложнее - единственный возможный способ - исключить эти геттеры и сеттеры. В противном случае вы не сможете переопределить эти методы в типе прокси, чтобы указать версию прокси этого вложенного объекта.

Подумайте об использовании RPC, если вы действительно хотите повторно использовать одни и те же типы на клиенте и сервере.

person Colin Alworth    schedule 06.04.2013
comment
Я понимаю вашу точку зрения. RPC лучше подходит для сложных сущностей, но это более утомительно. Службы RF настроить гораздо проще, и другой ответ соответствует моим требованиям. Благодарю Колина. - person ; 07.04.2013