Play Framework 2.3 → 2.5へのアップグレード

なんか今さらな感じがありますが備忘録として書いておきます。

基本

2.4でDIが導入になったため変更点が非常に大きいです。2.4→2.5はそこまで変更量は大きくない(はず)です。

以下が公式のマイグレーションガイドです。ちゃんと読めばこのブログを読む必要はない…はずです。私はちゃんと読みませんでした。

Play 2.4 Migration Guide
Play 2.5 Migration Guide

Play sbt pluginのアップグレード

project/plugins.sbt

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

本記事作成時点で2.5.4が最新だったので2.5.4にしました。

play-jsonのアップグレード

play-jsonを使っている場合、バージョンを古いままにしておくとTwirlテンプレートが正常にコンパイルできなくなったりします。一応、コンパイル時にも「バージョンが古いよ」という警告は出ますが最新にしておくと良いと思います。

というか、特にバージョンにこだわりが無ければlibraryDependenciesから消しましょう。どうせ依存関係に入ってきます。

コントローラーのインジェクション

Play 2.3まではコントローラーはobjectで定義していましたが、2.4からDIが導入されたのでclassで宣言します。

特に変なことをしていなければ「object」を「class」に書き換えていくだけでいい…はずです。

で、build.sbtに以下行を追加します。

build.sbt

routesGenerator := InjectedRoutesGenerator

これでインジェクションが有効になります。

デフォルトでobjectを使いたい場合は上記行をbuild.sbtに追加せず、代わりにroutesファイルのコントローラ名の頭に@を付けるとそのコントローラに関してだけインジェクションが有効になります。

Globalオブジェクトの廃止

GlobalもDIが導入されたことによって廃止されました。

以前、Globalに書いていた初期化コードは各インジェクション対象のクラスのコンストラクタに書くことになります。

その他、Globalを使って独自のエラーページを表示させていた場合は下記ページに従って

Handling errors

HttpErrorHandlerを継承したクラスを作り、以下のようにapplication.confでエラーハンドラとして設定します。

play.http.errorHandler = "com.example.ErrorHandler"

例えば以下のような感じです。

@Singleton
class ErrorHandler @Inject() (
                               env: Environment,
                               config: Configuration,
                               sourceMapper: OptionalSourceMapper,
                               router: Provider[Router]
                               ) extends DefaultHttpErrorHandler(env, config, sourceMapper, router) {

  override def onClientError(request: RequestHeader, statusCode: Int, message: String) = {
    Future.successful(
      Status(statusCode)(views.html.notFound(request.path))
    )
  }

  override def onServerError(request: RequestHeader, exception: Throwable) = {
    Future.successful(
    if(env.mode == play.api.Mode.Dev)
      InternalServerError(views.html.serverError(Some(exception)))
    else
      InternalServerError(views.html.serverError(None))
    )
  }
}

たぶん、開発モードで実行している時は例外発生時にスタックを表示させたいとかあるでしょうから、そういう場合は上記のとおりEnvironmentのmodeを参照して判定してください。Applicationからmodeを採取しようとしてエラーハンドラのクラスでApplicationのインスタンスをInjectionするとCircular Injectionになってるとエラーが出ます。

ログ出力設定

application.confでログレベルを制御する機能は廃止されました。普通にlogbackの設定ファイル(logger.xml)をconfの下に置いてください。

まとめ

忘れてる手順があるかもしれませんが、思ったより移行は面倒では無かったです。コンパイル時にいちいち警告を出してくれるので分かりやすいと思います。