2014-02-10 4 views
3

Вместо того, чтобы создавать сотни различных сервисов GWT-RPC и классов serviceAsync, я пытаюсь создать единую службу с использованием дженериков. Вот интерфейс:Использование Generics с GWT-RPC не работает должным образом

@RemoteServiceRelativePath("dispatch") 
public interface CommandService extends RemoteService 
{ 
    public <T> Result<T> execute(Command command, T target); 
} 

Здесь Command является перечисление всех различных команд, которые я могу выдавать, например, Login, Register, ChangePassword»и т.д. На стороне сервера, у меня есть HashMap из Command в качестве ключа, и класс 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); 

Здесь я получаю следующие ошибки:

ERROR: Deferred binding failed for 'com.xxx.CommandService'; expect subsequent failures

ERROR: Uncaught exception escaped com.google.gwt.event.shared.UmbrellaException: Exception caught: Deferred binding failed for 'com.xxx.CommandService' (did you forget to inherit a required module?)

Caused by: com.google.gwt.core.ext.UnableToCompleteException: (see previous log entries)

Как я могу выполнить то, что я пытаюсь сделать?

ответ

5

В клиентских приложениях GWT все типы должны быть известны во время компиляции. Наличие универсального метода, подобного тому, который вы описали, просто не будет работать.

Вы могли бы попробовать что-то вроде следующего

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

Вы потеряете безопасность типов и ограничивать вас немного, но это должно работать.

Request Factory может быть лучше в этом случае. Он предлагает много снисходительности относительно того, где серверный код выполняет фактическую работу.

В источнике GWT имеется образец образца Factory Factory. На веб-сайте gwtproject.org есть довольно четкие инструкции по получению исходного кода, here. Посмотрите файл README в каталоге eclipse. Это поможет вам начать работу.

Edit:

Как @ColinAlworth отметил, вы должны быть ОЧЕНЬ ОСТОРОЖНЫ при использовании простых интерфейсов в своих методах RPC. Вышеуказанный метод сообщает компилятору, что он должен иметь возможность отправлять каждому объекту Serializable по проводу, к которому он имеет доступ, и создаст сериализаторы и десериализаторы для каждого из них!

+6

Будьте очень осторожны с этим - вы явно говорит компилятору, что он может отправить * любой * сериализации объекта по проводам. Генератор RPC выберет любой Serializable, к которому имеет доступ GWT, и построит для него сериализаторы и десериализаторы и скомпилирует этот тип, даже если вы никогда не используете эти типы в другом месте проекта. –

+0

Спасибо за ловушку @ColinAlworth – Jonathan

1

Использование жанров и классов объектов для GWT-RPC является плохим подходом. Некоторое время он будет генерировать исключение для сериализации, иногда это не будет, но это не сработает. Причиной этого является то, что GWT создает во время компиляции белый список или политику сериализации.Для этого вам нужно знать точные классы, которые вы используете. Для получения более подробной информации об этом, проверьте ссылку ниже

Serialization Exception while making an RPC call

+0

Каков наилучший способ использования шаблона команды с GWT? –

+0

Шаблон команды - один из шаблонов проектирования, который рекомендуется для программирования с помощью gwt. Если вы заметили, даже пример AsyncCallback. Но для gwt -rpc вы не можете использовать шаблоны команд, которые включают Generics. Это должен быть конкретный класс, который реализует Serializable или IsSeralizable. –

+0

Я вижу. Но я не понимаю, как шаблон команды можно использовать для таких вещей, как кеширование запросов gwt в этом случае. Я смотрел видео на нем, где он создал интерфейс Action и 'Response'. Затем он создал интерфейс ContactService GWT, который принял в качестве своего аргумента и возвратил . Но я не понимаю, почему в этом случае необходимо использовать 'Action' и' Response'. И как его можно использовать для реализации кэширования? Есть идеи? –

Смежные вопросы