2016-08-19 5 views
2

非同期タスクを実行する必要があるアクションに問題があります。このアクションは、サーバが非同期タスク(doSearch()メソッド)によってブロックされないようにCompletionStageを返し、タスクが完了したらクライアントに応答するためにcomplete()を呼び出すことができます。ここでは、コントローラ/ Application.java内部アクションです:コンパイルエラー:要求のハンドラとしてCompetionStageを返すメソッドを使用できない

@BodyParser.Of(BodyParser.Json.class) 
public static CompletionStage<Result> search(String secret) { 
    CompletableFuture<Result> result = new CompletableFuture<>(); 
    if (!hasPermission(secret)) { 
     result.complete(unauthorized("Secret is incorrect.")); 
     return result; 
    } 
    JsonNode json = request().body().asJson(); 
    if (json == null) { 
     result.complete(badRequest("Expecting json data.")); 
     return result; 
    } 

    SearchRequestBody search = Json.fromJson(json, SearchRequestBody.class); 
    doSearch(search.body).thenApply(searchResults -> { 
     result.complete(ok(Json.toJson(searchResults))); 
     return null; 
    }); 
    return result; 
} 

ルートファイル:

# Home page 
GET /       controllers.Application.index 

# Map static resources from the /public folder to the /assets URL path 
GET  /assets/*file    controllers.Assets.at(path="/public", file) 

#PUT  /predict/:id    controllers.Application.predict() 

GET /search      controllers.Application.search 

エラー:

[info] Compiling 1 Java source to C:\Users\senok\IdeaProjects\Culinars\target\scala-2.11\classes... 
[info] Compiling 1 Scala source to C:\Users\senok\IdeaProjects\Culinars\target\scala-2.11\classes... 
[error] C:\Users\senok\IdeaProjects\Culinars\conf\routes:13: Cannot use a method returning java.util.concurrent.CompletionStage[play.mvc.Result] as a Handler for requests 
[error] GET /search      controllers.Application.search 
[error] C:\Users\senok\IdeaProjects\Culinars\conf\routes:13: not enough arguments for method createInvoker: (implicit hif: play.core.routing.HandlerInvokerFactory[java.util.concurrent.CompletionStage[play.mvc.Result]])play.core.routing.HandlerInvoker[java.util.concurrent.CompletionStage[play.mvc.Result]]. 
[error] Unspecified value parameter hif. 
[error] GET /search      controllers.Application.search 
[error] two errors found 
[error] (compile:compile) Compilation failed 
[error] application - 

! @715l00c2i - Internal server error, for (GET) [/search] -> 

play.sbt.PlayExceptions$CompilationException: Compilation error[Cannot use a method returning java.util.concurrent.CompletionStage[play.mvc.Result] as a Handler for requests] 
    at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na] 
    at play.sbt.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na] 
    at scala.Option.map(Option.scala:145) ~[scala-library-2.11.7.jar:na] 
    at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:49) ~[na:na] 
    at play.sbt.run.PlayReload$$anonfun$taskFailureHandler$1.apply(PlayReload.scala:44) ~[na:na] 
    at scala.Option.map(Option.scala:145) ~[scala-library-2.11.7.jar:na] 
    at play.sbt.run.PlayReload$.taskFailureHandler(PlayReload.scala:44) ~[na:na] 
    at play.sbt.run.PlayReload$.compileFailure(PlayReload.scala:40) ~[na:na] 
    at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17) ~[na:na] 
    at play.sbt.run.PlayReload$$anonfun$compile$1.apply(PlayReload.scala:17) ~[na:na] 

編集:ここにdoSearchです:

だけ
private static CompletableFuture<List<SearchResult>> doSearch(Map<String, String>[] args) { 
    CompletableFuture<List<SearchResult>> result = new CompletableFuture<>(); 
    List<SearchResult> results = new ArrayList<>(); 
    final int[] paramsLeft = new int[]{args.length}; 
    for (Map<String, String> param : args) { 
     if (!param.containsKey("type") 
       || !param.containsKey("uid") 
       || !param.containsKey("importance")) { 
      paramsLeft[0]--; 
      if (paramsLeft[0] == 0) 
       result.complete(results); 
     } else { 
      String nodeName = ""; 
      switch (param.get("type")) { 
       case "ingredient": 
        nodeName = "ingredients"; 
        break; 
       case "tag": 
        nodeName = "tags"; 
        break; 
       case "keyword": 
        nodeName = "keywords"; 
        break; 
       default: 
        paramsLeft[0]--; 
        if (paramsLeft[0] == 0) 
         result.complete(results); 
      } 
      DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child(nodeName).child(param.get("uid")); 
      ref.child("recipes").addListenerForSingleValueEvent(new ValueEventListener() { 
       @Override 
       public void onDataChange(DataSnapshot dataSnapshot) { 
        if (!dataSnapshot.exists()) { 
         paramsLeft[0]--; 
         if (paramsLeft[0] == 0) 
          result.complete(results); 
         return; 
        } 
        for (DataSnapshot recipe : dataSnapshot.getChildren()) { 
         SearchResult searchResult = new SearchResult(); 
         searchResult.uid = recipe.getKey(); 
         searchResult.matching = Double.parseDouble(param.get("importance")); 
         int index = results.indexOf(searchResult); 
         if (index > -1) 
          results.get(index).combine(searchResult); 
         else 
          results.add(searchResult); 
        } 
        paramsLeft[0]--; 
        if (paramsLeft[0] == 0) { 
         result.complete(results); 
        } 
       } 

       @Override 
       public void onCancelled(DatabaseError databaseError) { 
        paramsLeft[0]--; 
        if (paramsLeft[0] == 0) 
         result.complete(results); 
       } 
      }); 
     } 
    } 
    return result; 
} 
+0

「doSearch」メソッドコードを表示できますか? – Salem

+0

@Salemあなたが提案した変更は、まだコンパイルエラーに終わった。私はdoSearchを投稿しましたが、私はそれがそれと関係していることを非常に疑っています。 CompletionStage を返すので、コンパイラは関数を完全に拒否するため、バグのように見えます。私は今問題を解決した、私の答えで説明した。 – MrHappy

答えて

0

のコードを投稿してください取得する場合、我々はまだ保ち、それが代わりに検索結果を返すことができますそれは非同期です。

return result.get(); //Locks the thread until result.complete() is called. 
+0

これで問題が解決した場合は、問題の答えとしてマークしてください – Salem

0

あなたのメスの最後の部分を変更するこれにOD:

SearchRequestBody search = Json.fromJson(json, SearchRequestBody.class); 
return doSearch(search.body).thenApply(searchResults -> { 
    return ok(Json.toJson(searchResults)); 
}); 

すべてのアクションは、デフォルトでは、自分のCompletionStage内にラップされているので、あなたはまだコンパイルエラーがdoSearch

関連する問題