1. Qiita
  2. Items
  3. Scala

Play 2.3.xから2.4.x、Slick 2.xから3.1.xへの移行

  • 18
    Like
  • 0
    Comment
More than 1 year has passed since last update.

Play Java 歴 1 年くらいの私が、最近、プロジェクトで、Play Scala、Slickのバージョンアップを行いました。マイグレーションを行う方が、事前に知っておいた方が良いことについて記しておきます。なお、ここに記載されていることが全てではありませんので、マイグレーションガイドを参照ください。

Play 2.4.x への以降

移行の詳細については、マイグレーションガイドを参照。

ビルド方法の変更

project/plugins.sbt にあるPlayを以下に更新します。

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

Play 2.4 の対応 sbt バージョンは 0.13.8 です。project/build.properties を更新しましょう。

sbt.version=0.13.8

Javaは8のみサポート

6と7はサポート対象外になり、6または7でビルドしようとするとエラーになるようです。

Dependency Injectionのサポート

3.0 でグローバルな状態管理を完全に廃止することを目標にDIの導入を行っているようです。2.4から Guiceというライブラリを使ったDIをデフォルトでサポートし始めたようです。DIの詳細はドキュメントを参照。

対応する場合、まずbuild.sbtにルートジェネレータとして、DIに対応版を使うことを明記。

routesGenerator := InjectedRoutesGenerator

DI 対応の目印で conf/routes の Controller のメソッド名に @ をつけます。

GET        /some/path           @controllers.Application.index
  • DIのを使うことは @Inject で明記します。@injectJSR330 で決められた DI 用のアノテーション。
  • 共通に DI を使う用途は、後述のメッセージ国際化対応(messagesApi: MessagesApi)、DB の設定(dbConfigProvider: DatabaseConfigProvider)です。
class Application @Inject() (dbConfigProvider: DatabaseConfigProvider, messagesApi: MessagesApi) extends Controller with I18nSupport {

なお、コントローラを object(シングルトンオブジェクト)としていた場合、今後はclassにし、かつ @Singleton をつけることで、引き続きシングルトンとして扱うことが可能です。

@Singleton
class YoutSingletonClass @Inject(yourParameter: YourClass) {

国際化APIへの対応

Internationalization API が導入されました。ビューに表示するメッセージは言語ごとに設定ファイルとして用意し、 play.api.i18n.Messages としてコントローラやビューに渡すようになりました。詳細はドキュメント参照。

DIの仕組みでviewに注入するため、viewの先頭にmessageの宣言が必要です。

(implicit messages: Messages)

Controllerも messagesApi: play.api.i18n.Messages を渡すように修正が必要。

class Application @Inject() (dbConfigProvider: DatabaseConfigProvider, messagesApi: MessagesApi) extends Controller with I18nSupport {

また、conf/application.confのアプリケーション言語設定もi18nの方を使うように修正。

play.i18n.langs = [ "en" ]

Slick 3.0 への移行

詳細は Slick のマイグレーションガイドを参照。

buid.sbtの変更

  • play-slick のバージョンを変更します。
  • evolutions は別モジュールに切りだされたそうです。利用する場合は "evolutions"(ORM 共通)と "play-slick-evolutions"(Slickのevolutions)が必要です。
libraryDependencies ++= Seq(
  ...
  evolutions,
  "com.typesafe.play" % "play-slick_2.11" % "1.1.1",
  "com.typesafe.play" %% "play-slick-evolutions" % "1.1.1",
  ...
)

evolutiuonを止めたい場合は、conf/application.confに以下を設定。プロパティ名が変更されている点に注意。

play.evolutions.enabled=false

DBの設定

slick を使う場合、application.conf の設定名が変更。プロパティ名が変更されている点に注意。

slick.dbs.default.driver="slick.driver.H2Driver$"
slick.dbs.default.db.driver=org.h2.Driver
slick.dbs.default.db.url="jdbc:h2:mem:play"
slick.dbs.default.db.user=sa
slick.dbs.default.db.password=""

Slick ドライバの自動検出

これまでは以下の import で特定のドライバ用のAPIをインポートしていましたが、この方法は廃止されました。

import play.api.db.slick.Config.driver.simple._.

これからは application.conf で設定したものをフレームワークが自動検出し、DI で注入するようになりました。import driver.api._ の箇所で設定したドライバの API が利用できるようになります。

class Application @Inject() (dbConfigProvider: DatabaseConfigProvider, messagesApi: MessagesApi) extends Controller with I18nSupport {
  val dbConfig = dbConfigProvider.get[JdbcProfile]

  import dbConfig._
  import driver.api._

非同期クエリ実行のサポート

2.x系で使われていたDBAction、DBSessionRequest、DB.withSessionなどのAPIが廃止されました。

https://www.playframework.com/documentation/2.4.4/PlaySlick#Running-a-database-query-in-a-Controller

このドキュメントにあるように今後は、db.runというAPIを使います。これは Future を返すメソッドです。DB のクエリが非同期化され、コントローラのレスポンス部分も非同期化(Futureを返す)ようになっている点に注目。
例えば、あるまとまった処理を小分けてし、非同期処理し、結果がまとまったら返すみたいなことができ、スケールアウトさせることが容易になったといえます。

def index(name: String) = Action.async { implicit request =>
  val resultingUsers: Future[Seq[User]] = dbConfig.db.run(Users.filter(_.name === name).result)
  resultingUsers.map(users => Ok(views.html.index(users)))
}

以上です。本記事が、これからマイグレーションを行う方にとって参考になりましたら、幸いです。もし記事の内容で、気になる点、間違いなどありましたら、コメントいただけると嬉しいです。