Play! 2.0から2.1にアップデート
時代はPlay 2.1だよね(棒
Play 2.0から2.1にアップデートした。丸1日位かかったので、これからやる人に向けてちょっとメモ。
- 旧環境: Play 2.0.4
- 新環境: Play 2.1.1
なぜアップデートしようと思ったか
ちなみに、元々Play 2.1にアップデートするつもりじゃなかったんだけど、以下の理由から何となく・・・
- Eclipse 3.6 + Scala IDE 2.0の環境で、"Check for Updates"をしたら、Scala IDEの新しいのが出てたので何も考えずにアップデート
- 何かうまく動かない・・・調べてみたらScala IDE 3.0はEclipse 3.6では動かないとのこと
- Scala IDE 2.0に戻そうと思ったけど、Scala 2.8向けのしか無いぞ・・・
- Eclipse 4.2 + Scala IDE 3.0にすっか
- せっかくだし、Play 2.1にしてみるか
Eclipse 3.6でScala IDE 3.0にしちゃうと、以下の様なエラーが出る。Eclipse 3.6の場合はアップデート出来ないようにしとけよ!ってみんな思うらしい。
Could not open the editor: scala.tools.eclipse.ScalaPresentationReconciler cannot be cast to org.eclipse.jdt.internal.ui.text.JavaPresentationReconciler
Play, Scala, ライブラリの非互換性に対応する
Play 2.0から2.1にあたって、対応すべき点は、大雑把に言って以下の通り。
- Play 2.0と2.1間の非互換性
- Scala 2.9と2.10間の非互換性
- 使用しているライブラリのバージョンが上がることによる非互換性
Play自身に関しては、こちらのMigration Guideを参考に。
Scala 2.9と2.10に関する非互換性ってどっかにまとまってるのかな。とりあえず、Manifestに関するドキュメントはあったけど。
ライブラリに関しては、2.9で使えるバージョンと2.10で使えるが異なる場合が結構あって、その場合に非互換性がある場合がある。これはまぁライブラリ毎に対応する必要がある。
以降、順に説明していく。
Play自身に関する非互換性に対応
さっき触れたMigration Guideに目を通すこと。
plugins.sbt, build.properties
project/plugins.sbt で、sbt-pluginのバージョンを変更。2.1.1ですよ。
addSbtPlugin("play" % "sbt-plugin" % "2.1.1")
project/build.properties の、sbtのバージョンを記載。0.12.3 でいいんだよね。
sbt.version=0.12.3
Build.scala
次にBuild.scala を変更。
変更点をまとめておく。
- Play 2.0のPlayProjectが2.1ではplay.Projectに変わったらしい。
- 今まで標準で入っていたライブラリ群がモジュール化されて、個別にdependenciesに追加しなければいけなくなった。play.api.db.*とかAnormとか。
- mainLangは指定する必要ない(※)
変更後はこんな感じ(必要なところのみ記載)。
// import PlayProject._ //1: Play 2.0 import play.Project._ // 1: Play 2.1 object ApplicationBuild extends Build { //途中省略 val appDependenciesWebsite = Seq( jdbc, // 2関連 fooLibrary, barLibrary ) val website = play.Project( // ← 1関連 appName + "-website", appVersion, appDependenciesWebsite //3: 不要→ , mainLang = SCALA //以後省略
※mailLangつけてると以下のエラーが出た。
[error] /Users/k4200/greatapp/project/Build.scala:61: not found: value mainLang
Promise → Future
Play 2.0のPromiseはなくなって?ScalaのFutureになったよ。ただ、Migration Guideに書いてある例が非同期の例しか載ってなかったので、ここで自分の例も載せておく。
//2.0ではこんなことしてた WS.url("http://example.com/someapi").withQueryString(params:_*).get.map { response => // }.value.get //2.1ではこうした。 import scala.concurrent.Await import play.api.libs.concurrent.Execution.Implicits._ import scala.concurrent.duration.Duration val timeout = Duration("120 seconds") val future = WS.url("http://example.com/someapi").withQueryString(params:_*).get.map { response => // } Await.result(future, timeout)
もっといい方法ないすか?
JsonObjectの変更点
play.api.libs.json.Reads のシグニチャーが変わったよ。
// Play 2.0 def reads(json: JsValue): (String, String) = { ((json \ "foo").as[String], (json \ "bar").as[String]) } // Play 2.1 def reads(json: JsValue): JsResult[(String, String)] = { // JsResultを返す JsSuccess(((json \ "foo").as[String], (json \ "bar").as[String])) //JsSuccessでラップ }
使う時
// Play 2.0 val result = Json.fromJson[(String, String)](jsValue) // Play 2.1 val jsResult = Json.fromJson[(String, String)](jsValue) val result = jsResult.get //良い子のみなさんはgetOrElseとかasOptとか使って下さい。
Scala 2.9と2.10間の非互換
自分が引っかかったのは1つだけだと思う。
<% がなくなった?
specs2関連でこんなtraitを作って使ってた。
// Scala 2.9 trait UseFakeApplication extends AroundExample { class FakeApp extends FakeApplication() def around[R <% Result](r: =>R) = running(new FakeApp)(r) }
上のtraitを実装しているところが以下のようなエラーを出すようになった。
[error] /Users/k4200/greatapp/test/package/SomeClassSpec.scala:10: class SomeClassSpec needs to be abstract, since method around in trait AroundExample of type [T](t: => T)(implicit evidence$1: org.specs2.execute.AsResult[T])org.specs2.execute.Result is not defined
Seems that we are going to need to change the implementation of Around to, since <% is going to go away in scala 2.10
だって。以下のように書き換えたらOKだった。
// Scala 2.10 import org.specs2.execute.AsResult trait UseFakeApplication extends AroundExample { class FakeApp extends FakeApplication() def around[R: AsResult](r: =>R): Result = running(new FakeApp)(AsResult(r)) }
以前のrpscalaでScalaTest最高!って発表見てから、specs2は捨てたくなったけど、まぁ仕方ない。
その他
Play 2.1でプロジェクトを分割する方法はこちら。
自分はPlay 2.0の時からサブプロジェクトに分割してたんだけど、Play 2.1にしたら以下の様なエラーがでた。
[warn] Binary version (2.9.2) for dependency org.scala-lang#scala-library;2.9.2 [warn] in some-project#some-project_2.10;0.1-SNAPSHOT differs from Scala binary version in project (2.10). (snip) [error] error while loading Foo, class file needed by Foo is missing. [error] reference value meta of package annotation refers to nonexisting symbol.
Build.scalaを以下のように変更したらOKだった。
val bgtasks = Project( appName + "-bgtasks", file("bgtasks") ) .settings( scalaVersion := "2.10.1", // これを追加 libraryDependencies ++= appDependenciesBgtasks,
まとめ
PlayもScalaも開発が活発でどんどん便利になるけど、こういう移行作業はツライっす。この記事が何かの参考になれば幸い。