ドキュメント

§Play 2.6 移行ガイド

これは、Play 2.5 から Play 2.6 に移行するためのガイドです。以前のバージョンのPlayから移行する必要がある場合は、まずPlay 2.5移行ガイドに従う必要があります。

§移行方法

sbt で Play プロジェクトをロード/実行する前に、次の手順を実行して sbt ビルドを更新する必要があります。

§Playのアップグレード

project/plugins.sbtのPlayバージョン番号を更新して、Playをアップグレードします。

addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.x")

2.6.xの「x」は、使用するPlayのマイナーバージョンです。たとえば、2.6.0です。

§sbtを0.13.15にアップグレード

Play 2.6では、少なくともsbt 0.13.15へのアップグレードが必要です。sbtの0.13.15リリースには、多くの改善とバグ修正が含まれています(sbt 0.13.13の変更も参照してください)。

sbt 1.xは、Play 2.6.6からサポートされています。他のsbtプラグインを使用している場合は、sbt 1.xと互換性のある新しいバージョンがあるかどうかを確認する必要がある場合があります。

更新するには、project/build.propertiesを次のように変更します。

sbt.version=0.13.15

§Guice DIサポートが別のモジュールに移動

Play 2.6では、コアPlayモジュールにGuiceが含まれなくなりました。guicelibraryDependenciesに追加して、Guiceモジュールを構成する必要があります。

libraryDependencies += guice

§OpenIDサポートが別のモジュールに移動

Play 2.6では、コアPlayモジュールにplay.api.libs.openid(Scala)およびplay.libs.openid(Java)のOpenIDサポートが含まれなくなりました。これらのパッケージを使用するには、openIdlibraryDependenciesに追加します。

libraryDependencies += openId

§Play JSONが別のプロジェクトに移動

Play JSONは、https://github.com/playframework/play-jsonでホストされている別のライブラリに移動されました。Play JSONにはPlayの他の部分への依存関係がないため、主な変更点は、sbtビルドでPlayImportjson値が機能しなくなることです。代わりに、ライブラリを手動で指定する必要があります。

libraryDependencies += "com.typesafe.play" %% "play-json" % "2.6.0"

また、play-jsonはコアPlayライブラリとは別のリリースサイクルを持っているため、バージョンはPlayバージョンと同期しなくなりました。

§Play Iterateesが別のプロジェクトに移動

Play Iterateesは、https://github.com/playframework/play-iterateesでホストされている別のライブラリに移動されました。Play IterateesにはPlayの他の部分への依存関係がないため、主な変更点は、ライブラリを手動で指定する必要があることです。

libraryDependencies += "com.typesafe.play" %% "play-iteratees" % "2.6.1"

このプロジェクトには、IterateesをReactive Streamsと統合するサブプロジェクトもあります。次の依存関係も追加する必要がある場合があります。

libraryDependencies += "com.typesafe.play" %% "play-iteratees-reactive-streams" % "2.6.1"

:ヘルパークラスplay.api.libs.streams.Streamsplay-iteratees-reactive-streamsに移動し、現在はplay.api.libs.iteratee.streams.IterateeStreamsと呼ばれています。そのため、Iterateesの依存関係を追加し、必要に応じて新しいクラスを使用する必要がある場合があります。

最後に、Play Iterateesには別のバージョニングスキームがあるため、バージョンはPlayバージョンと同期しなくなりました。

§デフォルトのサーバーエンジンとしてのAkka HTTP

Playは、デフォルトのバックエンドとしてAkka-HTTPサーバーエンジンを使用するようになりました。何らかの理由で(たとえば、Nettyのネイティブトランスポートを使用している場合)、Nettyに戻す必要がある場合は、Nettyサーバーのドキュメントでその方法を参照してください。

詳しくは、Akka HTTPサーバーバックエンドをご覧ください。

§Akka HTTPサーバーのタイムアウト

Play 2.5.xには、デフォルトのサーバーバックエンドであったNettyサーバーのリクエストタイムアウト構成がありません。しかし、Akka HTTPには、アイドル状態の接続とリクエストの両方のタイムアウトがあります(詳細については、Akka HTTP設定ドキュメントを参照してください)。Akka HTTPドキュメントには次のように記載されています。

Akka HTTPには、悪意のある攻撃やプログラミングミスからサーバーを保護するためのさまざまな組み込みタイムアウトメカニズムが用意されています。

akka.http.server.idle-timeoutakka.http.server.request-timeout、およびakka.http.server.bind-timeoutのデフォルト値は、こちらで確認できます。Playには独自のタイムアウトを定義するための構成があるため、多くの503 Service Unavailableが表示され始めた場合は、構成をアプリケーションにとってより適切な値に変更できます。たとえば、

play.server.http.idleTimeout = 60s
play.server.akka.requestTimeout = 40s

§Scala Mode の変更

ScalaのModeは、列挙型からケースオブジェクトの階層にリファクタリングされました。このリファクタリングのため、ほとんどのScalaコードは変更されません。ただし、JavaコードでScalaのMode値にアクセスする場合は、次のように変更する必要があります。

// Consider this Java code
play.api.Mode scalaMode = play.api.Mode.Test();

次のように書き換える必要があります。

// Consider this Java code
play.api.Mode scalaMode = play.Mode.TEST.asScala();

JavaモードとScalaモード間の変換も簡単です。

// In your Java code
play.api.Mode scalaMode = play.Mode.DEV.asScala();

またはScalaコードで

play.Mode javaMode = play.api.Mode.Dev.asJava

また、play.api.Mode.Modeは非推奨になったため、代わりにplay.api.Modeを使用する必要があります。

§Writeable[JsValue] の変更

以前は、デフォルトのScala Writeable[JsValue]で暗黙的なCodecを定義でき、異なる文字セットを使用して書き込むことができました。application/jsonはテキストベースのコンテンツタイプのように機能しないため、これは問題になる可能性があります。Unicode文字セット(UTF-8UTF-16UTF-32)のみを許可し、多くのテキストベースのコンテンツタイプのようにcharsetパラメーターを定義しません。

現在、デフォルトのWriteable[JsValue]は暗黙的なパラメーターを受け取らず、常にUTF-8で書き込みます。これにより、ほとんどのユーザーがJSONにUTF-8を使用したいと考えているため、ほとんどのケースがカバーされます。また、JSONをバイト配列に書き込むためのより効率的な組み込みメソッドを簡単に使用できます。

以前の動作に戻す必要がある場合は、目的のコーデックとコンテンツタイプに対して、play.api.http.Writeable.writeableOf_JsValue(codec, contentType)を使用して任意のコーデックでWriteableを定義できます。

§Scalaコントローラーの変更

過去の慣用的なPlayコントローラーには、グローバル状態が必要でした。それが主に必要だったのは、グローバルのplay.api.mvc.ActionオブジェクトとBodyParsers#parseメソッドでした。

同じ構文を提供する、その状態を注入する新しい方法を備えた、いくつかの新しいコントローラークラスを提供しました。
- BaseController:実装クラスによって提供できる抽象ControllerComponentsを備えたトレイト。
- AbstractController:コンストラクターインジェクションを使用して注入できるControllerComponentsコンストラクターパラメーターを持つBaseControllerを拡張する抽象クラス。
- InjectedController:メソッドインジェクション(setControllerComponentsメソッドの呼び出し)を介してControllerComponentsを取得するBaseControllerを拡張するトレイト。GuiceのようなランタイムDIフレームワークを使用している場合、これは自動的に行われます。

ControllerComponentsは、通常コントローラーで使用されるコンポーネントをまとめるためのものです。また、ControllerHelpersを拡張し、独自のコンポーネントバンドルを注入して、アプリ独自のベースコントローラーを作成することもできます。Playでは、コントローラーが特定のトレイトを実装する必要はありません。

BaseController は、通常望ましい動作である、グローバルオブジェクトではなくインジェクトされたインスタンスを参照するように Action および parse を設定することに注意してください。

以下は、AbstractController を使用したコード例です。

class FooController @Inject() (components: ControllerComponents)
    extends AbstractController(components) {

  // Action and parse now use the injected components
  def foo = Action(parse.json) {
    Ok
  }
}

そして BaseController を使用した例です。

class FooController @Inject() (val controllerComponents: ControllerComponents) extends BaseController {

  // Action and parse now use the injected components
  def foo = Action(parse.json) {
    Ok
  }
}

そして InjectedController を使用した例です。

class FooController @Inject() () extends InjectedController {

  // Action and parse now use the injected components
  def foo = Action(parse.json) {
    Ok
  }
}

InjectedController は、setControllerComponents メソッドを呼び出すことで、ControllerComponents を取得します。このメソッドは JSR-330 準拠の依存性注入によって自動的に呼び出されます。コンパイル時注入で InjectedController を使用することは推奨しません。コントローラーをユニットテストで手動で広範囲にテストする場合も、依存関係を隠蔽するため InjectedController を避けることをお勧めします。

個々の依存関係を手動で渡したい場合は、代わりに依存関係や状態を持たない ControllerHelpers を拡張することができます。以下に例を示します。

class Controller @Inject() (
    action: DefaultActionBuilder,
    parse: PlayBodyParsers,
    messagesApi: MessagesApi
  ) extends ControllerHelpers {
  def index = action(parse.text) { request =>
    Ok(messagesApi.preferred(request)("hello.world"))
  }
}

§Scala ActionBuilder および BodyParser の変更

Scala の ActionBuilder トレイトは、ボディの型を型パラメータとして指定し、デフォルトのボディパーサーとして抽象メンバー parser を追加するように変更されました。ActionBuilder を変更し、ボディパーサーを直接渡す必要があります。

play.api.mvc.Action グローバルオブジェクトと BodyParsers#parse は非推奨になりました。これらは、インジェクション可能なトレイトである DefaultActionBuilder および PlayBodyParsers でそれぞれ置き換えられます。コントローラー内では、これらは新しい BaseController トレイトによって自動的に提供されます(上記の コントローラーの変更を参照)。

§Cookie

Java ユーザー向けに、新しいクッキーを作成するには、play.mvc.Http.Cookie.builder を使用することをお勧めします。以下に例を示します。

Http.Cookie cookie = Cookie.builder("color", "blue")
  .withMaxAge(3600)
  .withSecure(true)
  .withHttpOnly(true)
  .withSameSite(SameSite.STRICT)
  .build();

これはプレーンなコンストラクタ呼び出しよりも可読性が高く、将来クッキー属性を追加/削除する場合でもソース互換性があります。

§セッションおよびフラッシュに有効な SameSite 属性

クッキーは、CSRF を防止するために使用できる追加の SameSite 属性を持つことができるようになりました。可能な状態は 3 つあります。

さらに、セッションおよびフラッシュクッキーは、デフォルトで SameSite=Lax を使用するように変更しました。これは構成を使用して調整できます。たとえば、

play.http.session.sameSite = null // no same-site for session
play.http.flash.sameSite = "strict" // strict same-site for flash

: この機能は現在、多くのブラウザーでサポートされていません。したがって、この機能に依存すべきではありません。現在、SameSite をサポートしている主要なブラウザーは Chrome と Opera のみです。

§__Host および __Secure 接頭辞

__Host および __Secure クッキー名接頭辞のサポートも追加しました。

これは、クッキー名にこれらの接頭辞を使用している場合にのみ影響します。そうである場合、Play は、適切な属性が設定されていない場合、これらのクッキーをシリアル化およびデシリアル化するときに警告し、自動的に設定します。警告を削除するには、これらの接頭辞をクッキーに使用するのをやめるか、次のように属性を必ず設定してください。

§アセット

§コンパイル時 DI によるアセットのバインディング

コンパイル時 DI を使用している場合は、controllers.AssetsComponents をミックスインし、それを使用して assets: Assets コントローラーインスタンスを取得する必要があります。

class MyComponents(context: Context) extends BuiltInComponentsFromContext(context) with AssetsComponents {
  lazy val router = new Routes(httpErrorHandler, assets)
}

既存の lazy val assets: Assets がある場合は、削除できます。

§アセット設定

既存のユーザー向け API は変更されていませんが、アセットを見つけたり、構成でアセットディレクトリを設定したりするには、AssetsFinder API に移行することをお勧めします。

play.assets {
  path = "/public"
  urlPrefix = "/assets"
}

次に、ルートで以下のように記述できます。

# prefix must match `play.assets.urlPrefix`
GET /assets/*file           controllers.Assets.at(file)
GET /versionedAssets/*file  controllers.Assets.versioned(file)

引数リストの先頭にアセットパスを指定する必要はなくなりました。これは構成から読み込まれるようになったためです。

次に、テンプレートで AssetsFinder#path を使用して、アセットの最終パスを見つけることができます。

@(assets: AssetsFinder)

<img alt="hamburger" src="@assets.path("images/hamburger.jpg")">

Assets.versioned でリバースルートを引き続き使用できますが、提供されたアセット名を最終的なアセット名に変換するには、一部のグローバル状態が必要であり、複数のアプリケーションを同時に実行したい場合は問題になる可能性があります。

§フォームの変更

Play 2.6 以降、POSTPUT、または PATCH リクエストと組み合わせて bindFromRequest() を使用する場合、クエリ文字列パラメーターはフォームインスタンスにバインドされなくなります。

すでに 2.5 で非推奨になっていた静的メソッド(例:DynamicForm.form())は、このリリースで削除されました。引き続き使用する場合は、移行方法の詳細について Play 2.5 移行ガイドを参照してください。

§Java フォームの変更

play.data.Form インスタンスの errors() メソッドは非推奨になりました。代わりに、単純な List<ValidationError> を返す allErrors() を使用する必要があります。Map<String,List<ValidationError>> ではありません。Play 2.6 より前は .errors().get("key") を呼び出していたところは、.errors("key") を呼び出すだけで済みます。

今後は、フォームクラス内に実装された validate メソッド(通常はクロスフィールド検証に使用される)は、クラスレベルの制約の一部です。このような制約の使用方法の詳細については、高度な検証ドキュメントを参照してください。
既存の validate メソッドは、影響を受けるフォームクラスに @Validate を注釈し、validate メソッドの戻り型に応じて、該当する型引数を持つ Validatable インターフェースを実装することで、簡単に移行できます(すべて play.data.validation.Constraints で定義されています)。

戻り型 実装するインターフェース
String Validatable<String>
ValidationError Validatable<ValidationError>
List<ValidationError> Validatable<List<ValidationError>>
Map<String,List<ValidationError>>
(サポートされなくなりました。代わりに List を使用してください)
Validatable<List<ValidationError>>

たとえば、次のような既存のフォームは、

public class MyForm {
    //...
    public String validate() {
        //...
    }
}

次のように変更する必要があります。

import play.data.validation.Constraints.Validate;
import play.data.validation.Constraints.Validatable;

@Validate
public class MyForm implements Validatable<String> {
    //...
    @Override
    public String validate() {
        //...
    }
}

注意:「古い」validate メソッドは、他のすべての制約が成功した後にのみ呼び出されました。ただし、デフォルトでは、クラスレベルの制約は、成功したか失敗したかに関係なく、他の制約注釈と同時に呼び出されます。制約間の順序を(も)定義するには、制約グループを使用できます。

§JPA 移行の注意事項

JPA 移行の注意事項を参照してください。

§I18n 移行の注意事項

I18N API 移行を参照してください。

§キャッシュ API 移行の注意事項

キャッシュ API 移行を参照してください。

§Java 構成 API 移行の注意事項

Java 構成移行を参照してください。

§Scala 構成 API

Scala の play.api.Configuration API には、ConfigLoader を使用して任意の型をロードできる新しいメソッドが追加されました。これらの新しいメソッドは、構成ファイルに構成キーが存在することを前提としています。たとえば、次の古いコードは、

val myConfig: String = configuration.getString("my.config.key").getOrElse("default")

次のように変更する必要があります。

val myConfig: String = configuration.get[String]("my.config.key")

また、値 "default" は、my.config.key = default として構成に設定する必要があります。

または、デフォルト値を取得するためにコード内でカスタムロジックが必要な場合は、構成ファイルでデフォルトを null に設定し(my.config.key = null)、Option[T] を読み取ることができます。

val myConfigOption: Option[String] = configuration.get[Option[String]]("my.config.key")
val myConfig: String = myConfigOption.getOrElse(computeDefaultValue())

また、古い play.api.Configuration には、getBooleanList のような Java 型を返すメソッドがいくつかあります。可能であれば、代わりに Scala バージョンの get[Seq[Boolean]] を使用することをお勧めします。それが不可能な場合は、underlying Config オブジェクトにアクセスして、そこから getBooleanList を呼び出すことができます。

既存のメソッドの非推奨メッセージは、各メソッドを移行する方法も説明しています。 play.api.Configuration の適切な使用方法の詳細については、Scala 構成ドキュメントを参照してください。

§Play JSON API の変更

§JSON 配列インデックスルックアップ

Scala play-json API を使用している場合、JsLookup 暗黙クラスの動作方法に小さな変更がありました。たとえば、次のようなコードがある場合、

val bar = (jsarray(index) \ "bar").as[Bar]

ここで、index は配列インデックスで、jsarrayJsArray である場合、次は次のように記述する必要があります。

val bar = (jsarray \ index \ "bar").as[Bar]

これは、Scalaにおける他のコレクションのインデックス処理の動作と、JsArrayのインデックス処理の動作を一致させるために行われました。jsarray(index)メソッドは、指定されたインデックスの値が存在すればその値を返し、存在しなければ例外をスローするようになりました。

また、play-json APIにも小さな変更があり、play.api.data.validation.ValidationErrorplay.api.libs.json.JsonValidationErrorに変更されました。たとえば、次のようなコードがあった場合

ValidationError("Validation Error")

ここで、「Validation Error」がメッセージである場合、現在は次のように記述する必要があります。

JsonValidationError("Validation Error")

§削除されたAPI

§削除されたCrypto API

Crypto APIは、非推奨となっていたクラスであるplay.api.libs.Cryptoplay.libs.Crypto、およびAESCTRCrypterを削除しました。CryptoへのCSRF参照はCSRFTokenSignerに置き換えられました。セッションクッキーのCryptoへの参照はCookieSignerに置き換えられました。詳細については、CryptoMigration25を参照してください。

§Akkaの非推奨メソッドの削除

非推奨の静的メソッドであるplay.libs.Akka.systemおよびplay.api.libs.concurrent.Akka.systemが削除されました。依存性注入を使用してActorSystemのインスタンスを取得し、アクターシステムにアクセスしてください。

Scalaの場合

class MyComponent @Inject() (system: ActorSystem) {

}

Javaの場合

public class MyComponent {

    private final ActorSystem system;

    @Inject
    public MyComponent(ActorSystem system) {
        this.system = system;
    }
}

また、Play 2.6.xでは、Akka 2.5.xリリースシリーズを使用するようになりました。Akkaの2.4.xから2.5.xへの移行ガイドを参照し、必要に応じて自分のコードを適応させてください。

§削除されたYaml API

Play内部でplay.libs.Yamlを使用しなくなったため、これを削除しました。Play YAML統合のサポートがまだ必要な場合は、build.sbtsnakeyamlを追加する必要があります。

libraryDependencies += "org.yaml" % "snakeyaml" % "1.17"

そして、次のラッパーをコード内に作成します。

public class Yaml {

    private final play.Environment environment;

    @Inject
    public Yaml(play.Environment environment) {
        this.environment = environment;
    }

    /**
     * Load a Yaml file from the classpath.
     */
    public Object load(String resourceName) {
        return load(
            environment.resourceAsStream(resourceName),
            environment.classLoader()
        );
    }

    /**
     * Load the specified InputStream as Yaml.
     *
     * @param classloader The classloader to use to instantiate Java objects.
     */
    public Object load(InputStream is, ClassLoader classloader) {
        org.yaml.snakeyaml.Yaml yaml = new org.yaml.snakeyaml.Yaml(new CustomClassLoaderConstructor(classloader));
        return yaml.load(is);
    }

}

またはScalaの場合

class Yaml @Inject()(environment: play.api.Environment) {
  def load(resourceName: String) = {
    load(environment.resourceAsStream(resourceName), environment.classLoader)
  }

  def load(inputStream: InputStream, classLoader: ClassLoader) = {
    new org.yaml.snakeyaml.Yaml(new CustomClassLoaderConstructor(classloader)).load(inputStream)
  }
}

Playの代替DIライブラリに明示的に依存している場合、または独自のカスタムアプリケーションローダーを定義している場合は、変更は必要ありません。

PlayのDIサポートを提供するライブラリは、play.application.loader構成キーを定義する必要があります。外部DIライブラリが提供されていない場合、ApplicationLoaderを指すように設定しない限り、Playは起動を拒否します。

§非推奨のplay.Routesの削除

JavaScriptルーターを作成するために使用されていた非推奨のplay.Routesクラスが削除されました。新しいJavaまたはScalaのヘルパーを使用する必要があります。

§削除されたライブラリ

デフォルトのPlayディストリビューションを少し小さくするために、いくつかのライブラリを削除しました。以下のライブラリはPlay 2.6ではもはや依存関係ではなくなったため、使用する場合は手動でビルドに追加する必要があります。

§Joda-Timeの削除

java.time APIの使用を推奨するため、Playのコアからjoda-timeのサポートを削除しています。

PlayのScalaフォームライブラリには、いくつかのJodaフォーマットが含まれていました。移行したくない場合は、build.sbtjodaFormsモジュールを追加できます。

libraryDependencies += jodaForms

そして、対応するオブジェクトをインポートします。

import play.api.data.JodaForms._

play-jsonでJodaのサポートが必要な場合は、次の依存関係を追加できます。

libraryDependencies += "com.typesafe.play" %% "play-json-joda" % playJsonVersion

ここで、playJsonVersionは使用したいplay-jsonのバージョンです。Play 2.6.xはplay-json 2.6.xと互換性があるはずです。play-jsonは現在、独立したプロジェクトであることに注意してください(後述)。

import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._

§Joda-Convertの削除

Playはjoda-convertを内部的にいくつか使用していました。プロジェクトで使用している場合は、build.sbtに追加する必要があります。

libraryDependencies += "org.joda" % "joda-convert" % "1.8.1"

§XercesImplの削除

XML処理のために、PlayはXerces XMLライブラリを使用していました。最近のJVMはXercesを参照実装として使用しているため、削除しました。プロジェクトが外部パッケージに依存している場合は、単にbuild.sbtに追加できます。

libraryDependencies += "xerces" % "xercesImpl" % "2.11.0"

§H2の削除

Playの以前のバージョンでは、H2データベースがプリパッケージされていました。ただし、Playのコアを小さくするために、削除しました。H2を使用する場合は、build.sbtに追加できます。

libraryDependencies += "com.h2database" % "h2" % "1.4.193"

テストでのみ使用していた場合は、Testスコープを使用することもできます。

libraryDependencies += "com.h2database" % "h2" % "1.4.193" % Test

依存関係を追加すると、H2ブラウザは引き続き機能します。

§snakeyamlの削除

Playはplay.libs.Yamlを削除したため、snakeyamlへの依存関係が削除されました。まだ使用している場合は、build.sbtに追加してください。

libraryDependencies += "org.yaml" % "snakeyaml" % "1.17"

Yaml APIの削除に関する注意事項も参照してください。

§Tomcat-servlet-apiの削除

Playはtomcat-servlet-apiが不要になったため削除しました。まだ使用している場合は、build.sbtに追加してください。

libraryDependencies += "org.apache.tomcat" % "tomcat-servlet-api" % "8.0.33"

§fork-runの削除

sbt-fork-run-pluginは、寿命が尽きたActivatorユーティリティにのみ必要であったため、生成されなくなります。2.6では解決されなくなるため、完全に削除しても問題ありません。

§リクエスト属性

すべてのリクエストオブジェクトに属性が含まれるようになりました。リクエスト属性は、リクエストタグの代替です。タグは非推奨になったため、属性にアップグレードする必要があります。属性はタグよりも強力です。タグは文字列の保存のみをサポートしていましたが、属性を使用するとオブジェクトをリクエストに保存できます。

§リクエストタグの非推奨

タグは非推奨になっているため、タグの使用から属性の使用に移行する必要があります。移行はかなり簡単に行えるはずです。

最も簡単な移行パスは、タグからString型の属性に移行することです。

Javaの場合(移行前)

// Getting a tag from a Request or RequestHeader
String userName = req.tags().get("userName");
// Setting a tag on a Request or RequestHeader
req.tags().put("userName", newName);
// Setting a tag with a RequestBuilder
Request builtReq = requestBuilder.tag("userName", newName).build();

Javaの場合(移行後)

class Attrs {
  public static final TypedKey<String> USER_NAME = TypedKey.<String>create("userName");
}

// Getting an attribute from a Request or RequestHeader
String userName = req.attrs().get(Attrs.USER_NAME);
String userName = req.attrs().getOptional(Attrs.USER_NAME);
// Setting an attribute on a Request or RequestHeader
Request newReq = req.withTags(req.tags().put(Attrs.USER_NAME, newName));
// Setting an attribute with a RequestBuilder
Request builtReq = requestBuilder.attr(Attrs.USER_NAME, newName).build();

Scalaの場合(移行前)

// Getting a tag from a Request or RequestHeader
val userName: String = req.tags("userName")
val optUserName: Option[String] = req.tags.get("userName")
// Setting a tag on a Request or RequestHeader
val newReq = req.copy(tags = req.tags.updated("userName", newName))

Scalaの場合(移行後)

object Attrs {
  val UserName: TypedKey[String] = TypedKey("userName")
}
// Getting an attribute from a Request or RequestHeader
val userName: String = req.attrs(Attrs.UserName)
val optUserName: [String] = req.attrs.get(Attrs.UserName)
// Setting an attribute on a Request or RequestHeader
val newReq = req.addAttr(Attrs.UserName, newName)

ただし、適切であれば、Stringタグを非String値を持つ属性に変換することをお勧めします。タグを非Stringオブジェクトに変換すると、いくつかの利点があります。まず、コードがよりタイプセーフになります。これにより、コードの信頼性が向上し、理解しやすくなります。次に、属性に保存するオブジェクトには複数のプロパティを含めることができるため、複数のタグを1つの値に集約できます。第3に、タグを属性に変換すると、Stringからの値のエンコードとデコードが不要になり、パフォーマンスが向上する可能性があります。

class Attrs {
  public static final TypedKey<User> USER = TypedKey.<User>create("user");
}

Scalaの場合(移行後)

object Attrs {
  val UserName: TypedKey[User] = TypedKey("user")
}

§FakeRequest.withCookiesの呼び出しは、Cookiesヘッダーを更新しなくなりました

リクエストクッキーはリクエスト属性に保存されるようになりました。以前は、リクエストのCookieヘッダーStringに保存されていました。これには、クッキーが変更されるたびに、クッキーをヘッダーにエンコードおよびデコードする必要がありました。

クッキーがリクエスト属性に保存されるようになったため、クッキーを更新すると、新しいクッキー属性は変更されますが、Cookie HTTPヘッダーは変更されません。これは、withCookiesを呼び出すとヘッダーが更新されるという事実に依存している場合にのみ、テストに影響します。

古い動作がまだ必要な場合は、Cookies.encodeCookieHeaderを使用してCookieオブジェクトをHTTPヘッダーに変換し、そのヘッダーをFakeRequest.withHeadersで保存することができます。

§play.api.mvc.Security.username(Scala API)、session.usernameの変更

play.api.mvc.Security.username(Scala API)、session.username構成キー、および依存するアクションヘルパーは非推奨です。Security.usernameは構成からsession.usernameキーを取得するだけであり、ユーザー名を取得するために使用されるセッションキーを定義していました。静的機能を必要としたため削除されましたが、同じまたは同様の動作を自分で実装するのは非常に簡単です。

configuration.get[String]("session.username")を使用して、ユーザー名セッションキーを構成から自分で読み取ることができます。

Authenticated(String => EssentialAction)メソッドを使用している場合は、同様の処理を行う独自のアクションを簡単に作成できます。

def AuthenticatedWithUsername(action: String => EssentialAction) =
  WithAuthentication[String](_.session.get(UsernameKey))(action)

ここで、UsernameKeyは、ユーザー名に使用するセッションキーを表します。

§リクエストセキュリティ(Java API)ユーザー名プロパティが属性になりました

Javaリクエストオブジェクトには、JavaアクションにSecurity.Authenticatedアノテーションが追加されたときに設定されるusernameプロパティが含まれています。Play 2.6では、ユーザー名プロパティは非推奨になりました。ユーザー名プロパティメソッドは、ユーザー名をSecurity.USERNAME属性に保存するように更新されました。コードを更新して、Security.USERNAME属性を直接使用する必要があります。今後のPlayのバージョンでは、ユーザー名プロパティを削除します。

この変更の理由は、ユーザー名プロパティがSecurity.Authenticatedアノテーションの特別なケースとして提供されていたためです。属性が導入されたため、特別なケースは必要なくなりました。

既存のJavaコード

// Set the username
Request reqWithUsername = req.withUsername("admin");
// Get the username
String username = req1.username();
// Set the username with a builder
Request reqWithUsername = new RequestBuilder().username("admin").build();

更新されたJavaコード

import play.mvc.Security.USERNAME;

// Set the username
Request reqWithUsername = req.withAttr(USERNAME, "admin");
// Get the username
String username = req1.attr(USERNAME);
// Set the username with a builder
Request reqWithUsername = new RequestBuilder().putAttr(USERNAME, "admin").build();

§ルータータグが属性になりました

Router.Tags.*タグを使用した場合は、コードを更新して、新しいRouter.Attrs.HandlerDef(Scala)またはRouter.Attrs.HANDLER_DEF(Java)属性を使用する必要があります。既存のタグはまだ利用できますが、非推奨であり、今後のPlayのバージョンで削除されます。

この新しい属性には、タグに含まれているすべての情報を持つHandlerDefオブジェクトが含まれています。現在のタグはすべて、HandlerDefオブジェクトのフィールドに対応しています。

Javaタグ名 Scalaタグ名 HandlerDefメソッド
ROUTE_PATTERN RoutePattern path
ROUTE_VERB RouteVerb verb
ROUTE_CONTROLLER RouteController controller
ROUTE_ACTION_METHOD RouteActionMethod method
ROUTE_COMMENTS RouteComments comments

注意:この変更の一環として、HandlerDefオブジェクトは内部パッケージであるplay.core.routingから、パブリックAPIパッケージであるplay.api.routingに移動されました。

§play.api.libs.concurrent.Executionは非推奨です

play.api.libs.concurrent.Executionクラスは、内部でグローバルな可変状態を使用して「現在の」アプリケーションのExecutionContextを取得していたため、非推奨になりました。

以前と同じ暗黙的な動作を指定する場合は、依存性注入を使用してコンストラクターで暗黙的に実行コンテキストを渡す必要があります。

class MyController @Inject()(implicit ec: ExecutionContext) {

}

または、コンパイル時依存性注入を使用している場合はBuiltInComponentsから渡します。

class MyComponentsFromContext(context: ApplicationLoader.Context)
  extends BuiltInComponentsFromContext(context) {
  val myComponent: MyComponent = new MyComponent(executionContext)
}

ただし、一般的なケースでも実行コンテキストをインポートしたくない正当な理由がいくつかあります。一般的なケースでは、アプリケーションの実行コンテキストは、アクションのレンダリング、およびブロッキングAPI呼び出しやI/Oアクティビティを伴わないCPUバウンドのアクティビティの実行に適しています。データベースを呼び出したり、ネットワーク呼び出しを行ったりする場合は、独自のカスタム実行コンテキストを定義する必要があります。

カスタム実行コンテキストを作成する推奨される方法は、CustomExecutionContextを使用することです。これは、Akkaディスパッチャーシステム(java / scala)を使用しており、構成を通じて実行者を定義できます。

独自の実行コンテキストを使用するには、application.confファイル内のディスパッチャーへの完全パスを持つCustomExecutionContext抽象クラスを拡張します。

import play.api.libs.concurrent.CustomExecutionContext

class MyExecutionContext @Inject()(actorSystem: ActorSystem)
 extends CustomExecutionContext(actorSystem, "my.dispatcher.name")
import play.libs.concurrent.CustomExecutionContext;
class MyExecutionContext extends CustomExecutionContext {
   @Inject
   public MyExecutionContext(ActorSystem actorSystem) {
     super(actorSystem, "my.dispatcher.name");
   }
}

次に、必要に応じてカスタム実行コンテキストを注入します。

class MyBlockingRepository @Inject()(implicit myExecutionContext: MyExecutionContext) {
   // do things with custom execution context
}

カスタムスレッドプール構成の詳細については、スレッドプールのページを参照してください。また、CustomExecutionContextの使用については、JavaAsync / ScalaAsyncを参照してください。

§play.api.testヘルパーの変更

以下の非推奨のテストヘルパーが2.6.xで削除されました。

§Java API

§テンプレートヘルパーの変更

views/helper/requireJs.scala.htmlrequireJs テンプレートヘルパーは、設定にアクセスするために Play.maybeApplication を使用していました。

requireJs テンプレートヘルパーに、ヘルパーのminify版を使用するかどうかを示す追加パラメータ isProd が追加されました。

@requireJs(core = routes.Assets.at("javascripts/require.js").url, module = routes.Assets.at("javascripts/main").url, isProd = true)

§ファイル拡張子とMIMEタイプのマッピングの変更

ファイル拡張子からMIMEタイプへのマッピングは reference.conf に移動し、play.http.fileMimeTypes 設定の下で完全に設定を通じて扱われるようになりました。以前は、リストは play.api.libs.MimeTypes の下でハードコードされていました。

play.http.fileMimeTypes の設定は、三重引用符で囲まれた単一の文字列として定義されていることに注意してください。これは、いくつかのファイル拡張子(例:c++)がHOCONを破壊する構文を持っているためです。

カスタムMIMEタイプを追加するには、HOCON文字列値連結を使用してください。

play.http.fileMimeTypes = ${play.http.fileMimeTypes} """
  foo=text/bar
"""

追加のMIMEタイプのために mimetype.foo=text/bar として定義された設定を許可する構文があります。これは非推奨であり、上記の構成を使用することをお勧めします。

§Java API

Http.Context.current().fileMimeTypes() メソッドが内部的に Results.sendFile やファイル拡張子からコンテンツタイプをルックアップするその他のメソッドに提供されています。移行は必要ありません。

§Scala API

play.api.libs.MimeTypes クラスは play.api.http.FileMimeTypes インターフェースに変更され、実装は play.api.http.DefaultFileMimeTypes に変更されました。

ファイルを送信するすべての結果は、暗黙的に FileMimeTypes を受け取るようになりました。例えば:

implicit val fileMimeTypes: FileMimeTypes = ...
Ok(file) // <-- takes implicit FileMimeTypes

FileMimeTypes の暗黙的なインスタンスは、便利なバインディングを提供するために、BaseController (およびそのサブクラスである AbstractController、サブトレイトである InjectedController) によって ControllerComponents クラスを通じて提供されます。

class SendFileController @Inject() (cc: ControllerComponents) extends AbstractController(cc) {

  def index() = Action { implicit request =>
     val file = readFile()
     Ok(file)  // <-- takes implicit FileMimeTypes
  }
}

ユニットテストで完全に構成された FileMimeTypes インスタンスを直接取得することもできます。

val httpConfiguration = new HttpConfigurationProvider(Configuration.load(Environment.simple)).get
val fileMimeTypes = new DefaultFileMimeTypesProvider(httpConfiguration.fileMimeTypes).get

または、カスタムインスタンスを取得することもできます。

val fileMimeTypes = new DefaultFileMimeTypesProvider(FileMimeTypesConfiguration(Map("foo" -> "text/bar"))).get

§デフォルトフィルター

Playには、設定を通じて定義されたデフォルトの有効なフィルターセットが付属しています。プロパティ play.http.filters がnullの場合、デフォルトは play.api.http.EnabledFilters になり、play.filters.enabled 設定プロパティで完全修飾クラス名によって定義されたフィルターをロードします。

Play自体では、play.filters.enabled は空のリストです。ただし、filtersライブラリは、PlayFilters という名前のAutoPluginとしてsbtに自動的にロードされ、次の値を play.filters.enabled プロパティに追加します。

これは、新しいプロジェクトでは、CSRF保護 (ScalaCsrf / JavaCsrf)、SecurityHeaders、および AllowedHostsFilter がすべて自動的に定義されることを意味します。

§デフォルトフィルターの効果

デフォルトフィルターは、プロジェクトに「デフォルトで安全な」構成を提供するように設定されています。

これらのフィルターは有効にしたままにする必要があります。これらはアプリケーションのセキュリティを高めます。

既存のプロジェクトでこれらのフィルターを有効にしていなかった場合、いくつかの構成が必要になり、関連するエラーや失敗に慣れていない可能性があります。移行を支援するために、各フィルター、その機能、および必要な構成について説明します。

§CSRFFilter

CSRFフィルターについては、ScalaCsrfJavaCsrf で説明されています。POSTリクエストでチェックされるCSRFトークンをフォームに追加することにより、クロスサイトリクエストフォージェリ攻撃から保護します。

§デフォルトで有効になっている理由

CSRFは、実装にほとんどスキルを必要としない非常に一般的な攻撃です。https://github.com/Manc/play-scala-csrf で、Playを使用したCSRF攻撃の例を見ることができます。

§どのような変更が必要ですか?

CSRF.formField などのCSRFフォームヘルパーを使用していない既存のプロジェクトから移行する場合、CSRFフィルターからのPUTおよびPOSTリクエストで「403 Forbidden」が表示される場合があります。

フォームテンプレートに CSRF.formField を追加すると、エラーが解決されます。AJAXを使用してリクエストを作成する場合は、CSRFトークンをHTMLページに配置し、Csrf-Token ヘッダーを使用してリクエストに追加できます。

この動作を確認するには、logback.xml<logger name="play.filters.csrf" value="TRACE"/> を追加してください。

また、PlayでSameSite Cookieを有効にすると、CSRF攻撃に対する追加の防御を提供できます。

§SecurityHeadersFilter

SecurityHeadersFilter は、リクエストにHTTPヘッダーを追加することにより、クロスサイトスクリプティングおよび クリックジャッキング攻撃を防ぎます。

§デフォルトで有効になっている理由

ブラウザベースの攻撃は非常に一般的であり、セキュリティヘッダーはそれらの攻撃を阻止するのに役立つ多層防御を提供できます。

§どのような変更が必要ですか?

デフォルトの「Content-Security-Policy」設定は非常に厳格であり、最も便利な設定を見つけるために実験する必要がある可能性があります。Content-Security-Policy設定は、ブラウザでのJavaScriptとリモートフレームの表示方法を変更します。Content-Security-Policyヘッダーを変更するまで、埋め込みのJavaScriptまたはCSSはWebページにロードされません。

有効にしたくない場合は、次のようにContent-Security-Policyを無効にできます。

play.filters.headers.contentSecurityPolicy=null

CSP-Useful は、一般的なコンテンツセキュリティポリシーに関する優れたリソースです。リクエストごとにカスタムCSP nonceを追加するなど、埋め込みJavaScriptに対する他の潜在的なソリューションがあることに注意してください。

他のヘッダーはそれほど侵入的ではなく、一般的なWebサイトでは問題を引き起こす可能性は低いですが、シングルページアプリケーションではCookieやレンダリングの問題を引き起こす可能性があります。Mozillaには、URLにヘッダー名を使用し、各ヘッダーについて詳しく説明するドキュメントがあります。たとえば、X-Frame-Optionsの場合は、https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Optionsにアクセスしてください。

play.filters.headers {

    # The X-Frame-Options header. If null, the header is not set.
    frameOptions = "DENY"

    # The X-XSS-Protection header. If null, the header is not set.
    xssProtection = "1; mode=block"

    # The X-Content-Type-Options header. If null, the header is not set.
    contentTypeOptions = "nosniff"

    # The X-Permitted-Cross-Domain-Policies header. If null, the header is not set.
    permittedCrossDomainPolicies = "master-only"

    # The Content-Security-Policy header. If null, the header is not set.
    contentSecurityPolicy = "default-src 'self'"

    # The Referrer-Policy header. If null, the header is not set.
    referrerPolicy = "origin-when-cross-origin, strict-origin-when-cross-origin"

    # If true, allow an action to use .withHeaders to replace one or more of the above headers
    allowActionSpecificHeaders = false
}

§AllowedHostsFilter

AllowedHostsFilterは、許可されたホストのホワイトリストを追加し、ホワイトリストに一致しないホストを持つすべてのリクエストに400(不正なリクエスト)応答を送信します。

§デフォルトで有効になっている理由

これは開発で使用する重要なフィルターです。DNSリバインディング攻撃は、開発者のPlayインスタンスに対して使用できるためです。localhostで実行されているサーバーがどのように短期的なDNSリバインディングによって攻撃されるかについては、Rails Webconsole DNS Rebindingを参照してください。

§どのような変更が必要ですか?

localhost以外の場所でPlayアプリケーションを実行している場合は、接続元のホスト名/IPを明示的に許可するようにAllowedHostsFilterを構成する必要があります。これは、環境を変更する場合に特に重要です。通常、開発環境ではlocalhostで実行しますが、ステージング環境と本番環境ではリモートで実行するためです。

play.filters.hosts {
  # Allow requests to example.com, its subdomains, and localhost:9000.
  allowed = [".example.com", "localhost:9000"]
}

§フィルターへの追加

デフォルトリストに追加するには、+= を使用します。

play.filters.enabled+=MyFilter

play.api.http.DefaultHttpFilters を拡張して独自のフィルターを定義した場合は、EnabledFilters を独自のリストとコード内で結合することもできるため、以前に定義したプロジェクトは通常どおりに機能します。

class Filters @Inject()(enabledFilters: EnabledFilters, corsFilter: CORSFilter)
  extends DefaultHttpFilters(enabledFilters.filters :+ corsFilter: _*)

§デフォルトフィルターのテスト

複数のフィルターが有効になっているため、すべてのテストが合格し、リクエストが有効であることを確認するために、機能テストをわずかに変更する必要がある場合があります。たとえば、Host HTTPヘッダーがlocalhostに設定されていないリクエストは、AllowedHostsFilterに合格せず、代わりに400 Forbidden応答を返します。

§AllowedHostsFilterでのテスト

AllowedHostsFilterフィルターが自動的に追加されるため、機能テストにはHost HTTPヘッダーを追加する必要があります。

FakeRequest または Helpers.fakeRequest を使用している場合、Host HTTPヘッダーは自動的に追加されます。play.mvc.Http.RequestBuilder を使用している場合は、ヘッダーを手動で追加するための独自の行を追加する必要がある場合があります。

RequestBuilder request = new RequestBuilder()
        .method(GET)
        .header(HeaderNames.HOST, "localhost")
        .uri("/xx/Kiwi");

§CSRFFilterでのテスト

CSRFFilterフィルターが自動的に追加されるため、CSRF.formField を含むTwirlテンプレートをレンダリングするテスト(例:

@(userForm: Form[UserData])(implicit request: RequestHeader, m: Messages)

<h1>user form</h1>

@request.flash.get("success").getOrElse("")

@helper.form(action = routes.UserController.userPost()) {
  @helper.CSRF.formField
  @helper.inputText(userForm("name"))
  @helper.inputText(userForm("age"))
  <input type="submit" value="submit"/>
}

リクエストにCSRFトークンを含める必要があります。Scala APIでは、これは play.api.test.CSRFTokenHelper._ をインポートすることで行われます。これにより、play.api.test.FakeRequestwithCSRFToken メソッドが追加されます。

import play.api.test.CSRFTokenHelper._

class UserControllerSpec extends PlaySpec with GuiceOneAppPerTest {
  "UserController GET" should {

    "render the index page from the application" in {
      val controller = app.injector.instanceOf[UserController]
      val request = FakeRequest().withCSRFToken
      val result = controller.userGet().apply(request)

      status(result) mustBe OK
      contentType(result) mustBe Some("text/html")
    }
  }
}

Java APIでは、これはplay.mvc.Http.RequestBuilder インスタンスで CSRFTokenHelper.addCSRFToken を呼び出すことによって行われます。

requestBuilder = CSRFTokenHelper.addCSRFToken(requestBuilder);

§デフォルトフィルターの無効化

デフォルトフィルターを無効にする最も簡単な方法は、application.conf でフィルターのリストを手動で設定することです。

play.filters.enabled=[]

これは、デフォルトのフィルターを通過させたくない機能テストがある場合に役立つ場合があります。

すべてのフィルタークラスを削除したい場合は、disablePlugins メカニズムを使用して無効にできます。

lazy val root = project.in(file(".")).enablePlugins(PlayScala).disablePlugins(PlayFilters)

または、EnabledFilters を置き換えることでも可能です。

play.http.filters=play.api.http.NoHttpFilters

GuiceApplicationBuilder を含む機能テストを作成していて、デフォルトのフィルターを無効にしたい場合は、configure を使用して設定を通じてすべてのフィルターまたは一部のフィルターを無効にできます。

GuiceApplicationBuilder().configure("play.http.filters" -> "play.api.http.NoHttpFilters")

§コンパイル時デフォルトフィルター

コンパイル時依存性注入を使用している場合、デフォルトのフィルターは実行時ではなくコンパイル時に解決されます。

つまり、BuiltInComponents トレイトには抽象メソッドである httpFilters メソッドが含まれるようになりました。

trait BuiltInComponents {

  /** A user defined list of filters that is appended to the default filters */
  def httpFilters: Seq[EssentialFilter]
}

デフォルトのフィルターリストは play.filters.HttpFiltersComponents で定義されています。

trait HttpFiltersComponents
     extends CSRFComponents
     with SecurityHeadersComponents
     with AllowedHostsComponents {

   def httpFilters: Seq[EssentialFilter] = Seq(csrfFilter, securityHeadersFilter, allowedHostsFilter)
}

ほとんどの場合、HttpFiltersComponents をミックスインし、独自のフィルターを追加することになるでしょう。

class MyComponents(context: ApplicationLoader.Context)
  extends BuiltInComponentsFromContext(context)
  with play.filters.HttpFiltersComponents {

  lazy val loggingFilter = new LoggingFilter()
  override def httpFilters = {
    super.httpFilters :+ loggingFilter
  }
}

リストから要素をフィルタリングしたい場合は、次のようにできます。

class MyComponents(context: ApplicationLoader.Context)
  extends BuiltInComponentsFromContext(context)
  with play.filters.HttpFiltersComponents {
  override def httpFilters = {
    super.httpFilters.filterNot(_.getClass == classOf[CSRFFilter])
  }
}

§コンパイル時デフォルトフィルターの無効化

デフォルトのフィルターを無効にするには、play.api.NoHttpFiltersComponents をミックスインします。

class MyComponents(context: ApplicationLoader.Context)
   extends BuiltInComponentsFromContext(context)
   with NoHttpFiltersComponents
   with AssetsComponents {

  lazy val homeController = new HomeController(controllerComponents)
  lazy val router = new Routes(httpErrorHandler, homeController, assets)
}

§JWTサポート

Playのクッキーエンコーディングは、内部でJSON Web Token(JWT)を使用するように切り替えられました。JWTには、HMAC-SHA-256による自動署名や、セッションクッキーが特定の時間枠外で再利用されないようにするための自動的な「有効期限前」と「有効期限後」の日付チェックのサポートなど、多くの利点があります。

詳細については、セッションクッキーの設定ページを参照してください。

Playのクッキーエンコーディングは、「フォールバック」クッキーエンコーディングメカニズムを使用しており、JWTエンコードされたクッキーを読み込み、JWT解析が失敗した場合はURLエンコードされたクッキーを読み込もうとするため、既存のセッションクッキーをJWTに安全に移行できます。この機能は、FallbackCookieDataCodec トレイトにあり、DefaultSessionCookieBaker および DefaultFlashCookieBaker で活用されています。

§レガシーサポート

JWTエンコードされたクッキーの使用はシームレスであるはずですが、必要に応じて、application.confファイルで play.api.mvc.LegacyCookiesModule に切り替えることで、URLエンコードされたクッキーエンコーディングに戻すことができます。

play.modules.disabled+="play.api.mvc.CookiesModule"
play.modules.enabled+="play.api.mvc.LegacyCookiesModule"

§カスタム CookieBakers

Playで使用されているカスタムクッキー(CookieBaker[T] トレイトを使用)がある場合は、カスタムクッキーベイカーにどのようなエンコーディングを使用するかを指定する必要があります。

ブラウザで見つかった形式との間で Map[String, String] をエンコードおよびデコードするメソッドは、CookieDataCodec に抽出されています。3つの実装があります。FallbackCookieDataCodecJWTCookieDataCodec、または UrlEncodedCookieDataCodec であり、それぞれHMACによるURLエンコード、JWT、または「署名済みまたはJWTを読み込み、JWTを書き込む」コーデックを表します。

また、JWTConfigurationParser を使用して設定へのパスを指定した JWTConfiguration ケースクラスを提供するか、デフォルトの場合は JWTConfiguration() を使用する必要があります。

@Singleton
class UserInfoCookieBaker @Inject()(service: UserInfoService,
                                    val secretConfiguration: SecretConfiguration)
  extends CookieBaker[UserInfo] with JWTCookieDataCodec {

  override val COOKIE_NAME: String = "userInfo"

  override val isSigned = true

  override def emptyCookie: UserInfo = new UserInfo()

  override protected def serialize(userInfo: UserInfo): Map[String, String] = service.encrypt(userInfo)

  override protected def deserialize(data: Map[String, String]): UserInfo = service.decrypt(data)

  override val path: String = "/"

  override val jwtConfiguration: JWTConfiguration = JWTConfigurationParser()
}

§非推奨の Futures メソッド

次の play.libs.concurrent.Futures 静的メソッドは非推奨となりました。

代わりに、依存性注入された Futures のインスタンスを使用する必要があります。

class MyClass {
    @Inject
    public MyClass(play.libs.concurrent.Futures futures) {
        this.futures = futures;
    }

    CompletionStage<Double> callWithOneSecondTimeout() {
        return futures.timeout(computePIAsynchronously(), Duration.ofSeconds(1));
    }
}

§更新されたライブラリ

§Netty 4.1

Nettyはバージョン4.1にアップグレードされました。これは主に、バージョン4.0がplay-wsのスタンドアロンモジュールへの移行によってシェーディングされたためです。したがって、Netty ServerとNetty 4.0に依存するライブラリを使用している場合は、ライブラリの新しいバージョンへのアップグレードを試すか、Akka Serverの使用を開始することをお勧めします。

また、何らかの理由でNettyクラスを直接使用している場合は、この新しいバージョンに合わせてコードを調整する必要があります。

§FluentLeniumとSelenium

FluentLeniumライブラリがバージョン3.2.0に更新され、Seleniumが3.3.1に更新されました(changelogはこちらを参照してください)。以前にSeleniumのWebDriver APIを使用していた場合は、何もする必要はありません。こちらの発表で詳細を確認してください。
FluentLeniumライブラリを使用していた場合は、テストを再度機能させるために、いくつかの構文を変更する必要がある場合があります。コードを適応させる方法の詳細については、FluentLeniumの移行ガイドを参照してください。

§HikariCP

HikariCPが更新され、新しい構成 initializationFailTimeout が導入されました。この新しい構成は、現在非推奨となっている initializationFailFast を置き換えるために使用する必要があります。HikariCP changelog および initializationFailTimeout のドキュメントを参照して、この新しい構成の使用方法をより深く理解してください。

§その他の構成変更

いくつかの構成変更があります。古い構成パスは通常、まだ機能しますが、それらを使用すると、実行時に非推奨の警告が出力されます。変更されたキーの概要を以下に示します。

古いキー 新しいキー
play.crypto.secret play.http.secret.key
play.crypto.provider play.http.secret.provider
play.websocket.buffer.limit play.server.websocket.frame.maxLength

次へ: メッセージの移行


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