§Java 遷移指南
為了更適合 Java 8 生態系統,並允許 Play Java 使用者在應用程式中更慣用 Java,Play 已改用許多 Java 8 類型,例如 CompletionStage
和 Function
。Play 也有新的 Java API,例如 EssentialAction
、EssentialFilter
、Router
、BodyParser
和 HttpRequestHandler
。
§新的 Java API
有幾個 API 變更可以容納用 Java 編寫的過濾器和 HTTP 要求處理常式,特別是 HttpRequestHandler
介面。如果您使用 Scala 處理這些元件,您仍然可以自由使用 Scala API(如果您願意)。
§過濾器 API
建立過濾器時,您很可能會使用 EssentialAction
。您可以使用 Filter
API 或較低階的 EssentialFilter
API,它作用於 EssentialAction
。
§HttpRequestHandler 和 ActionCreator
HttpRequestHandler
實際上存在於 Play 2.4 中,但現在它有不同的用途。createAction
和 wrapAction
方法已移至稱為 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.Context
、Http.Session
等)不再傳遞給不同的執行緒環境。
更多資訊請見此處
§已棄用的靜態 API
在 Play 2.5 中,已棄用多個靜態 API,建議改用依賴項注入元件。使用靜態全域狀態不利於測試和模組化,建議您改用依賴項注入來存取這些 API。您應參閱 Play 2.4 遷移指南 中的清單,以找出靜態 API 的等效依賴項注入元件。
後續:加密遷移指南
在這個文件中發現錯誤?此頁面的原始程式碼可在 此處 找到。在閱讀 文件指南 後,請隨時提交拉取要求。有問題或建議要分享?請前往 我們的社群論壇 與社群展開對話。