2016-11-18 10 views
0

exceptionally CompletionStageのメソッド内で例外を再実行することはできないようです。Java 8 CompletionStage例外的に例外を戻す

私は例外の特定の種類をチェックする必要があり、そうでない場合、私はそれをバック再スローする必要が

Future<JsonNode> futureSite = someClient.getSite(siteId, queryParams); 

CompletionStage<JsonNode> outcome = FutureConverters.toJava(futureSite); 

return outcome.thenApplyAsync((siteJson) -> { 
      Site site = Json.fromJson(siteJson, Site.class); 
      try { 
       return function.apply(site); 
      } catch (RequestException e) { 
       return e.result; 
      } 
     }, httpExecutionContext.current()).exceptionally(throwable -> { 
      if(throwable instanceof SomeClientException) { 
       if(((SomeClientException) throwable).httpStatusCode == 404) { 
        return entityNotFound("Site", siteId); 
       } 
      } 


// let JSON parsing failures and other errors bubble up, TODO play2.5 


     throw throwable; 
     }); 

throw throwableエラーうち、おそらく戻って再スローすることができるようになるどのようなインターフェースunhandledException java.lang.Throwable

を言って例外?それとも良い方法がありますか?

更新:

BaseController.java : 
     protected class RequestException extends Exception { 
      private static final long serialVersionUID = -2154871100650903869L; 

      public Result result; 

      public RequestException(Result result) { 
       this.result = result; 
      } 
     } 

     @FunctionalInterface 
     protected interface RequestFunction<T, R> { 
      R apply(T t) throws RequestException; 
     } 

    protected CompletionStage<Result> performWithSite(final Long siteId, RequestFunction<Site, Result> function) { 
      QueryParams queryParams = QueryParams.create(); 
      Future<JsonNode> futureSite = someClient.getSite(siteId, queryParams); 

      CompletionStage<JsonNode> outcome = FutureConverters.toJava(futureSite); 

      return handleSpecific(
        outcome.thenApplyAsync(siteJson -> { 
         Site site = Json.fromJson(siteJson, Site.class); 
         try { 
          return function.apply(site); 
         } catch (RequestException e) { 
          return e.result; 
         } 
        }, httpExecutionContext.current()), 
        throwable -> throwable instanceof SomeClientException 
          && ((SomeClientException)throwable).httpStatusCode == 404, 
        () -> entityNotFound("Site", siteId)); 
     } 

     protected Result entityNotFound(String entityName, String id) { 
    // building our custom error model. 
    Error e = new Error(
        Http.Status.NOT_FOUND, 
        ErrorCode.ENTITY_NOT_FOUND, 
        ErrorCodes.NOT_FOUND, new String[]{entityName, id}); 

      return notFound(e.asJson()); 
     } 

ので、上記のコードの本質は、私は次のとおりです。私は以下のようにホルガーからアドバイスをしようとしたが、私は実際にこれを再スロー可能性がどの時点ではまだ確認していない

someClientにアクセスして、サイトが存在し、クライアントがSomeClientExceptionをスローできるかどうかを確認する必要があります。

Controller.java 

     public Result destroy(Long siteId, Long productId){ 
      return performWithSite(siteId, site -> { 
       productWriter.deleteProduct(siteId, productId); 
       return noContent(); 
      }).toCompletableFuture().exceptionally(e -> { 
       Logger.error(e+"exception"); 
       throw e.getCause(); 
       // above line errors out as unhandledException java.lang.throwable, I need the NotFoundException which is contained within the CompletionException to be thrown. 
      }); 
     } 

//上記のコントローラコードでは、クライアントにリモート呼び出しを行ってサイトが存在するかどうかを確認した後、製品を削除する必要があります。

productWriter.deleteProduct(siteId, productId)はまだ投げるかもしれないNotFoundExceptionか、私は戻ってそれを再スローする必要がある何か他のもの... ので、コントローラのコードから再スローされる例外は、呼び出しチェーンにおける当社のカスタム例外ハンドラをピックアップしていること。

"return 404 when deleting a nonexistent Product" { 
     when(productDAO.findBySiteAndProductId(anyLong(), anyLong())) thenReturn null 

     a[NotFoundException] should be thrownBy { controller.destroy(0L, 1L) } 
    } 
+0

質問はプレイ固有ではないと思います –

答えて

3

私の知る限り、何の組み込みソリューションはありません。

は、ここに私のテストケースです。 CompletionStageの連鎖方法に渡すことができるすべての関数タイプは、チェックされていない例外に限定されています。 (それは既にでない限り)CompletionExceptionにラップする必要がありますCompletionStageブロックからスロー

return handleSpecific(
    outcome.thenApplyAsync(siteJson -> { 
     Site site = Json.fromJson(siteJson, Site.class); 
     try { 
      return function.apply(site); 
     } catch (RequestException e) { 
      return e.result; 
     } 
    }, httpExecutionContext.current()), 
    throwable -> throwable instanceof SomeClientException 
       && ((SomeClientException)throwable).httpStatusCode == 404, 
    () -> entityNotFound("Site", siteId)); 
+0

ホルガーありがとうございました。 _if(p.test(t))result.complete(s.get()); _ _function_外部を評価するときにスローされる例外を伝播するのに役立ちますか?したがって、私たちはカスタム例外ハンドラを定義しています。関数内で例外がスローされると、CompletionException(これはコードの上にあります)の原因となり、再スローされますか? – hackmabrain

+0

他の意見はありますか? – hackmabrain

+0

元のコードでは 'return entityNotFound(" Site "、siteId);を' if'ステートメント内に書いていますので、条件が満たされても例外は伝播されませんが値が返されます。これはまさにsitedコード 'if(p.test(t))result.complete(s.get());'も同様です。述部が満たされていれば、サプライヤーから返された値が結果になります。 – Holger

0

すべての例外:あなたはあなた自身のユーティリティメソッドを建てことができます。

public static <T> CompletionStage<T> handleSpecific(
    CompletionStage<T> previousStage, Predicate<Throwable> p, Supplier<T> s) { 

    CompletableFuture<T> result = new CompletableFuture<>(); 
    previousStage.whenComplete((value,throwable)->{ 
     if(throwable == null) result.complete(value); 
     else { 
      Throwable t = throwable; 
      if(t instanceof CompletionException) { 
       t = t.getCause(); 
       if(t == null) t = throwable; 
      } 
      if(p.test(t)) result.complete(s.get()); 
      else result.completeExceptionally(throwable); 
     } 
    }); 
    return result; 
} 

この溶液を同様に使用することができます。ほとんどの場合、CompletionStageはチェックされていない例外のためにそれ自体を行い、CompletionExceptionは特に内部二重ラップを避けるために処理されます。

また、exceptionallyでは、チェーン内の前のブロックの数によっては例外がラップされているかどうかわからないことがあります。