Lagom framework/потоковый ответ/websocket/pathCall/дескриптор/создатель вместо функции

У меня есть моя служба, объявленная таким образом:

public interface BlogQueryService extends Service {

  public ServiceCall<String, Source<String, ?>> tick(int interval);
  public ServiceCall<String, Source<String, ?>> tock();
  public ServiceCall<NotUsed, Source<PostSummary, ?>> newPosts();
  public ServiceCall<String, Source<PostSummary, ?>> getPostSummaries();

  @Override
  default Descriptor descriptor() {
    return named("blog-query").with(
      //pathCall("/api/bloggie/tick/:interval", this::tick),
      pathCall("/api/bloggie/tock", tock())
      //pathCall("/api/bloggie/newPosts", this::newPosts),
      //pathCall("/api/bloggie/postSummaries", this::getPostSummaries)
    ).withAutoAcl(true);
  }
}

Галочка работает. Так нет.

Когда я вызываю его с помощью клиента веб-сокета (для ws://localhost:9000/api/bloggie/tock), я получаю ответ «undefined», что указывает на то, что сопоставление для этого URL-адреса не найдено.

После некоторых экспериментов выяснилось, почему: галочка работает, потому что у нее есть параметр url (интервал :). Галочка не работает, потому что у нее нет параметра url. Серьезно, pathCall требует, чтобы у вас был параметр в вашем URL-адресе? Поэтому я проверил API сервиса: http://www.lagomframework.com/documentation/1.0.x/api/java/com/lightbend/lagom/javadsl/api/Service.html

Есть несколько перегруженных объявлений pathCall. По-видимому, галочка использует этот:

static <Request,Response,A> Descriptor.Call<Request,Response> pathCall(String pathPattern, akka.japi.function.Function<A,ServiceCall<Request,Response>> methodRef) 

Итак, из подписи, да, требуется, чтобы метод принимал параметр. Итак, если метод (такой как tock) не принимает параметр, привязка завершится ошибкой во время выполнения. Поэтому я думаю, мне нужно использовать этот вместо этого:

static <Request,Response> Descriptor.Call<Request,Response> pathCall(String pathPattern, akka.japi.function.Creator<ServiceCall<Request,Response>> methodRef)

Проблема в том... я не знаю как. Я не видел ни одного примера использования akka.japi.function.Creator в pathCall.

Я пробовал это:

  default Descriptor descriptor() {
    return named("blog-query").with(
      pathCall("/api/bloggie/tick/:interval", this::tick),
      pathCall("/api/bloggie/tock", new Creator<ServiceCall<String, Source<String, ?>>> () {
          public ServiceCall<String, Source<String, ?>> create() {
              return tock();
          }
      })
      //pathCall("/api/bloggie/newPosts", this::newPosts),
      //pathCall("/api/bloggie/postSummaries", this::getPostSummaries)
    ).withAutoAcl(true);
  }

Он компилируется. Но во время выполнения выдает ошибку:

com.google.inject.CreationException: Unable to create injector, see the following errors:

1) Error in custom provider, java.lang.IllegalStateException: Unable to resolve method for service call with ID PathCallId{pathPattern='/api/bloggie/tock'}. Ensure that the you have passed a method reference (ie, this::someMethod). Passing anything else, for example lambdas, anonymous classes or actual implementation classes, is forbidden in declaring a service descriptor.
  at com.lightbend.lagom.javadsl.server.ServiceGuiceSupport.bindServices(ServiceGuiceSupport.java:43) (via modules: com.google.inject.util.Modules$OverrideModule -> sample.bloggie.impl.BlogServiceModule)
  while locating com.lightbend.lagom.internal.server.ResolvedServices

Заранее спасибо!


Я только что провел несколько экспериментов... Все скомпилировано, но ни один из них не работает....

namedCall("/api/bloggie/tock", this::tock)

Результат: Компиляция прошла успешно. Время выполнения: путь неизвестен (без привязки (?)).

Затем я попытался

pathCall("/api/bloggie/tock", () -> this.tock())

Результат: исключение.

com.google.inject.CreationException: Unable to create injector, see the following errors:
1) Error in custom provider, scala.MatchError: Request (of class sun.reflect.generics.reflectiveObjects.TypeVariableImpl)
  at com.lightbend.lagom.javadsl.server.ServiceGuiceSupport.bindServices(ServiceGuiceSupport.java:43) (via modules: com.google.inject.util.Modules$OverrideModule -> sample.bloggie.impl.BlogServiceModule)
  while locating com.lightbend.lagom.internal.server.ResolvedServices
    for parameter 1 at com.lightbend.lagom.internal.server.ServiceRegistrationModule$RegisterWithServiceRegistry.<init>(ServiceRegistrationModule.scala:55)
  at com.lightbend.lagom.internal.server.ServiceRegistrationModule.bindings(ServiceRegistrationModule.scala:29):
Binding(class com.lightbend.lagom.internal.server.ServiceRegistrationModule$RegisterWithServiceRegistry to self eagerly) (via modules: com.google.inject.util.Modules$OverrideModule -> play.api.inject.guice.GuiceableModuleConversions$$anon$1)
  while locating com.lightbend.lagom.internal.server.ServiceRegistrationModule$RegisterWithServiceRegistry

Затем я попробовал:

public ServiceCall<NotUsed, Source<String, ?>> tock(Void x);

Результат: исключение

com.google.inject.CreationException: Unable to create injector, see the following errors:

1) Error in custom provider, java.lang.IllegalArgumentException: Don't know how to serialize ID class java.lang.Void
  at com.lightbend.lagom.javadsl.server.ServiceGuiceSupport.bindServices(ServiceGuiceSupport.java:43) (via modules: com.google.inject.util.Modules$OverrideModule -> sample.bloggie.impl.BlogServiceModule)

Обновление: «Решено» (частично). Выяснил, что это работает:

pathCall("/tock", this::tock)

Я могу открыть его, используя этот URL: ws://localhost:9000/tock

Итак... у меня не может быть хорошо структурированного URL-адреса для тех функций, которые возвращают поток, когда этим функциям не нужны параметры? По крайней мере на данный момент (?).


ОБНОВЛЕНИЕ: похоже, эта проблема возникает не только с pathCall. Я столкнулся с той же проблемой с остальным вызовом. Это не работает (без привязки):

public ServiceCall<NotUsed, PSequence<PostSummary>> getPostSummaries();
...
restCall(Method.GET, "/api/bloggie/postSummaries", this::getPostSummaries)

Этот работает:

public ServiceCall<NotUsed, PSequence<PostSummary>> getPostSummaries();
...
restCall(Method.GET, "/postSummaries", this::getPostSummaries)

Спасибо!


person Cokorda Raka    schedule 15.05.2016    source источник


Ответы (1)


Итак, во-первых, namedCall следует использовать только в том случае, если вам не нужен путь. Вы вызываете вызов службы напрямую, а это значит, что вам небезразличен путь, поэтому вам нужно использовать pathCall или restCall.

Это должно работать:

pathCall("/api/bloggie/tock", this::tock)

Кроме того, я думаю, что вы не вставляете полные ошибки. Убедитесь, что вы проверили правую часть списка ошибок Guice, это должно точно объяснить, в чем проблема, во многих из вышеперечисленных случаев проблема заключается в том, что вы передаете не ссылку на метод, вы передаете лямбда , и сообщение об ошибке должно говорить об этом.

person James Roper    schedule 16.05.2016
comment
Привет.... Извини... наконец, попробовав и попробовав, понял... это была моя вина. Я объявил в другой и конечной точке конфликт..... restCall(Method.GET, /api/bloggie/:id, this::getPost), дело закрыто. :) - person Cokorda Raka; 16.05.2016
comment
Я имею в виду... чтобы избежать конфликта, который я сейчас использую: restCall(Method.GET, /api/yeaaaahh/postSummaries, this::getPostSummaries), - person Cokorda Raka; 16.05.2016