ドキュメント

§Java移行ガイド

Java 8のエコシステムにより適合させ、Play JavaユーザーがアプリケーションでJavaをより慣用的に使用できるようにするために、PlayはCompletionStageFunctionなどのいくつかのJava 8型を使用するように切り替えました。Playには、EssentialActionEssentialFilterRouterBodyParserHttpRequestHandler用の新しいJava APIもあります。

§新しいJava API

特にHttpRequestHandlerインターフェースにおいて、JavaでフィルターとHTTPリクエストハンドラーを作成できるようにするためのAPI変更がいくつかあります。これらのコンポーネントにScalaを使用している場合は、必要に応じてScala APIを自由に使用できます。

§フィルターAPI

フィルターを作成するときは、ほとんどの場合、EssentialActionを使用します。Filter APIまたは、EssentialActionで動作する下位レベルのEssentialFilter APIを使用できます。

§HttpRequestHandlerとActionCreator

HttpRequestHandlerはPlay 2.4に実際に存在していましたが、現在は異なる目的を果たしています。createActionメソッドとwrapActionメソッドは、ActionCreatorという新しいインターフェースに移動され、HttpRequestHandlerでは非推奨になりました。これらのメソッドはJavaアクションにのみ適用され、コントローラーのメソッド呼び出しへのリクエストをインターセプトするために使用されますが、すべてのリクエストではありません。

2.5では、HttpRequestHandlerの主な目的は、リクエストが到着した直後にリクエストのハンドラーを提供することです。これはScalaの実装が行うことと一致するようになり、JavaユーザーがすべてのHTTPリクエストの処理をインターセプトする方法を提供します。通常、HttpRequestHandlerはルーターを呼び出してリクエストのアクションを検索するため、新しいAPIを使用すると、ルーターに送信する前にJavaでリクエストをインターセプトできます。

§アクション内でのCompletionStageの使用

HTTP.Contextがスコープ内にとどまるように、Action内でJava CompletionStageを使用する場合は、HTTP実行コンテキストを実行者として明示的に指定する必要があります。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:ラムダ内でスローされるチェック例外によって発生するエラーを修正します。

Playの関数インターフェースとは異なり、Java 8の関数インターフェースでは、チェック例外をスローすることはできません。ラムダ式がチェック例外をスローする場合は、コードを変更する必要があります。(チェック例外をスローしない場合は、コードをそのままにしておくことができます。)

コンパイラーエラーが多数発生する可能性がありますが、コードを再び動作させるのは非常に簡単です。Play 2.4コードが、データベースを停止するためにF.Callback0ラムダを使用していると仮定しましょう

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

Play 2.5では、onCloseメソッドはF.Callback0の代わりにjava.lang.Runnable引数を取るように変更されました。Runnableはチェック例外をスローできないため、上記のコードはPlay 2.5ではコンパイルされません。

コードをコンパイルするには、チェック例外(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を使用する場合は、プロジェクトの依存関係として含めるか、2つクラスからソースをプロジェクトにコピーすることで含めることができます。

§F.PromiseをJava 8のCompletionStageに置き換え

F.Promiseを使用するAPIは、標準のJava 8 CompletionStageクラスを使用するようになりました。

§移行方法

ステップ1:F.Promiseを返すコードをすべて、代わりにCompletionStageを返すように変更します。移行を容易にするため、F.PromiseCompletionStageインターフェースも実装します。つまり、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(またはHttp.Contextをキャプチャする場合は、HttpExecution#defaultContext()を指定したhandleAsync
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は、PlayのF.Option型の代わりに、Java 8のOptionalクラスを使用するように変換されました。F.Option型は削除されました。

§移行方法

F.Option を使用しているコードを Optional に置き換えてください。2つの型は似ていますが、APIが異なるため、コードを更新する必要があります。2つの型の主な違いは、F.Optionjava.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を学習することを強く推奨します。

§スレッドローカル属性

Http.ContextHttp.Sessionなどのスレッドローカル属性は、CompletionStageおよび*Asyncコールバックで使用した場合、異なる実行コンテキストに渡されなくなりました。
詳細については、こちらを参照してください。

§非推奨のstatic API

Play 2.5では、いくつかのstatic APIが非推奨となり、代わりに依存性注入コンポーネントを使用することが推奨されています。staticなグローバル状態を使用することはテスト容易性とモジュール性を損なうため、これらのAPIへのアクセスには依存性注入に移行することを推奨します。静的APIに対応する依存性注入コンポーネントについては、Play 2.4移行ガイドのリストを参照してください。

次へ: 暗号化移行ガイド


このドキュメントにエラーを見つけましたか?このページのソースコードはこちらにあります。ドキュメントガイドラインを読んだ後、お気軽にプルリクエストを送信してください。質問や共有したいアドバイスがありますか?コミュニティフォーラムにアクセスして、コミュニティとの会話を始めてください。