文件

§Java 遷移指南

為了更適合 Java 8 生態系統,並允許 Play Java 使用者在應用程式中更慣用 Java,Play 已改用許多 Java 8 類型,例如 CompletionStageFunction。Play 也有新的 Java API,例如 EssentialActionEssentialFilterRouterBodyParserHttpRequestHandler

§新的 Java API

有幾個 API 變更可以容納用 Java 編寫的過濾器和 HTTP 要求處理常式,特別是 HttpRequestHandler 介面。如果您使用 Scala 處理這些元件,您仍然可以自由使用 Scala API(如果您願意)。

§過濾器 API

建立過濾器時,您很可能會使用 EssentialAction。您可以使用 Filter API 或較低階的 EssentialFilter API,它作用於 EssentialAction

§HttpRequestHandler 和 ActionCreator

HttpRequestHandler 實際上存在於 Play 2.4 中,但現在它有不同的用途。createActionwrapAction 方法已移至稱為 ActionCreator 的新介面,並在 HttpRequestHandler 中已標示為不建議使用。這些方法僅套用於 Java 動作,且用於攔截對控制項方法呼叫的請求,但並非所有請求。

在 2.5 中,HttpRequestHandler 的主要目的是在請求進入後立即提供請求處理常式。這現在與 Scala 實作一致,並提供一種方法讓 Java 使用者攔截所有 HTTP 請求的處理。通常,HttpRequestHandler 會呼叫路由器來尋找請求的動作,因此新的 API 允許您在請求傳送至路由器之前,在 Java 中攔截該請求。

§在動作中使用 CompletionStage

動作中使用 Java CompletionStage 時,您必須明確提供 HTTP 執行內容作為執行器,以確保 HTTP.Context 保持在範圍內。如果您未提供 HTTP 執行內容,則在呼叫 request() 或依賴於 Http.Context 的其他方法時,您將收到「此處沒有可用的 HTTP 內容」錯誤。

您可以透過依賴注入提供 play.libs.concurrent.HttpExecutionContext 執行個體

public class Application extends Controller {
    @Inject HttpExecutionContext ec;

    public CompletionStage<Result> index() {
        someCompletableFuture.supplyAsync(() -> { 
          // do something with request()
        }, ec.current());
    }
}

§使用 Java 8 函式類型取代函式類型

Play 2.5 的重大變更之一是盡可能使用標準 Java 8 類別。所有函式類型都已替換為其 Java 8 對應類型,例如 F.Function1<A,R> 已替換為 java.util.function.Function<A,R>

轉移到 Java 8 類型應能與其他 Java 函式庫以及 Java 8 中的內建功能有更好的整合。

§如何遷移

步驟 1:將所有參照 Play 函式介面的程式碼變更為參照 Java 8 介面。

您需要變更明確提到類似 F.Function1 類型的程式碼。例如

void myMethod(F.Callback0 block) { ... }

變更為

void myMethod(Runnable block) { ... }

下表顯示所有變更

舊介面 新介面
F.Callback0 java.lang.Runnable
F.Callback<A> java.util.function.Consumer<A>
F.Callback2<A,B> java.util.function.BiConsumer<A,B>
F.Callback3<A,B,C> Java 8 中沒有對應類型,考慮使用 akka.japi.function.Function3
F.Predicate<A> java.util.function.Predicate<A>
F.Function0<R> java.util.function.Supplier<R>
F.Function1<A,R> java.util.function.Function<A,R>
F.Function2<A,B,R> java.util.function.BiFunction<A,B,R>

步驟 2:修正 lambda 內引發的檢查式例外狀況所造成的任何錯誤。

與 Play 函式介面不同,Java 8 函式介面不允許引發檢查式例外狀況。如果您的 lambda 運算式引發檢查式例外狀況,則您需要變更程式碼。(如果您不引發檢查式例外狀況,則可以不變更程式碼。)

您可能會收到許多編譯器錯誤,但讓您的程式碼再次運作相當容易。假設您的 Play 2.4 程式碼使用 F.Callback0 lambda 來停止資料庫

onClose(() -> {
    database.stop(); // <-- can throw an IOException
})

在 Play 2.5 中,onClose 方法已變更為採用 java.lang.Runnable 參數,而非 F.Callback0。由於 Runnable 無法擲出核取例外,因此上述程式碼無法在 Play 2.5 中編譯。

若要讓程式碼能編譯,您可以變更 lambda 程式碼以捕捉核取例外 (IOException),並將其包裝在未核取例外 (RuntimeException) 中。Runnable 可以擲出未核取例外,因此程式碼現在可以編譯。

onClose(() -> {
    try {
        database.stop(); // <-- can throw an IOException
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
})

如果您不喜歡在程式碼中加入 try-catch 區塊,您可以使用 Durian 函式庫的 Errors 類別,讓它為您處理例外。

例如,您可以取得與上述相同的行為,將核取例外轉換為未核取例外,使用以下程式碼

onClose(Errors.rethrow().wrap(database::stop));

Durian 也提供其他行為,例如 記錄例外 或撰寫 您自己的例外處理常式。如果您想使用 Durian,您可以將它包含為 專案中的相依性,或從 兩個 類別 中複製原始程式碼到您的專案。

§以 Java 8 的 CompletionStage 取代 F.Promise

使用 F.Promise 的 API 現在使用標準 Java 8 CompletionStage 類別。

§如何遷移

步驟 1:將所有傳回 F.Promise 的程式碼變更為傳回 CompletionStage。為了協助遷移,F.Promise 也實作了 CompletionStage 介面,這表示任何傳回 Promise 的現有程式碼仍可從已遷移至使用 CompletionStage 的程式碼呼叫。

步驟 2:F.Promise 中相關的靜態方法替換為等效的方法(其中許多使用 play.libs.concurrent.Futures 輔助函式,或 CompletableFuture 上的靜態方法)

F.Promise 方法 替代方案
Promise.wrap scala.compat.java8.FutureConverters.toJava
Promise.sequence Futures.sequence
Promise.timeout Futures.timeout
Promise.pure CompletableFuture.completedFuture
Promise.throwing 建構 CompletableFuture 並使用 completeExceptionally
Promise.promise CompletableFuture.supplyAsync
Promise.delayed Futures.delayed

步驟 3:將現有的實例方法替換為 CompletionStage 上的等效方法

F.Promise CompletionStage
applyToEither
onRedeem thenAcceptAsync
map thenApplyAsync
transform handleAsync
zip thenCombine(並手動建構一個元組)
fallbackTo handleAsync 接著 thenCompose(Function.identity())
recover exceptionally(或 handleAsync 搭配 HttpExecution#defaultContext(),如果您想要擷取 Http.Context)。
recoverWith recover 相同,然後使用 .thenCompose(Function.identity())
onFailure whenCompleteAsync(如果需要,請使用 HttpExecution#defaultContext()
flatMap thenComposeAsync(需要時使用 HttpExecution#defaultContext()
filter thenApplyAsync 並手動實作篩選器(需要時使用 HttpExecution#defaultContext()

這些變更已在 F.Promise 的 Javadoc 中詳細說明。

§已將 F.Option 取代為 Java 8 的 Optional

Play Java API 已轉換為使用 Java 8 Optional 類別,而非 Play 的 F.Option 類型。F.Option 類型已移除。

§如何變更

將使用 F.Option 的程式碼替換為 Optional。這兩種類型很類似,但其 API 不同,因此您需要更新程式碼。這兩種類型之間的主要差異在於,F.Option 繼承 java.util.Collection,而 Optional 則沒有。

以下是簡短的表格,有助於您進行變更

F.Option Optional
F.Option.None() Optional.empty()
F.Option.Some(v) Optional.ofNullable(v)
o.isDefined() o.isPresent()
o.isEmpty() !o.isPresent()
o.get() o.get()
o.getOrElse(f) o.orElseGet(f)o.orElse(v)
o.map(f) o.map(f)

Optional 有更多的組合器,因此如果您還不熟悉,我們強烈建議您了解其 API

§執行緒區域變數

當與 CompletionStage*Async 回呼搭配使用時,執行緒區域變數(例如 Http.ContextHttp.Session 等)不再傳遞給不同的執行緒環境。
更多資訊請見此處

§已棄用的靜態 API

在 Play 2.5 中,已棄用多個靜態 API,建議改用依賴項注入元件。使用靜態全域狀態不利於測試和模組化,建議您改用依賴項注入來存取這些 API。您應參閱 Play 2.4 遷移指南 中的清單,以找出靜態 API 的等效依賴項注入元件。

後續:加密遷移指南


在這個文件中發現錯誤?此頁面的原始程式碼可在 此處 找到。在閱讀 文件指南 後,請隨時提交拉取要求。有問題或建議要分享?請前往 我們的社群論壇 與社群展開對話。