Documentation

You are viewing the documentation for the 2.2.0 release in the 2.2.x series of releases. The latest stable release series is 2.4.x.

§Play 2.1 移行ガイド

Play 2.0.x アプリケーションを Play 2.1.0 に移行するためには、まず project/plugins.sbt 内でPlayの sbt-plugin のバージョンを上げましょう。

addSbtPlugin("play" % "sbt-plugin" % "2.1.0")

次に project/Build.scala 内で PlayProject の代わりに新しい play.Project を使うように修正しましょう。

import を記述します。

import play.Project._

main プロジェクトの生成部分を次のように変更します。

val main = play.Project(appName, appVersion, appDependencies).settings(

project/build.properties ファイルを次のようにアップデートします。

sbt.version=0.12.2

最後に Play 2.1.0 のディストリビューションに含まれる play コマンドを起動して、プロジェクトを一旦 clean して、そして再コンパイルしましょう。

play clean
play ~run

もし何らかのコンパイルエラーが発生したら、このドキュメントを参考にして、エラーの原因となった非推奨機能、互換性のない変更などを発見することができます。

§ビルドファイルへの変更

Play 2.1 では今まで以上にモジュール化が進められました。そのため、これからはアプリケーションに必要なモジュールへの依存性を明示的に指定する必要があります。デフォルトの play.Project には Play の核となるたった一つのコアモジュールへの依存性のみが定義されています。それ以外のモジュールは必要に応じて選択しましょう。 Play 2.1 で新たに切りだされたモジュールは次の通りです。

Play 2.1 の典型的な Build.scala ファイルの内容は次のようになります。

import sbt._
import Keys._
import play.Project._

object ApplicationBuild extends Build {

    val appName         = "app-name"
    val appVersion      = "1.0"

    val appDependencies = Seq(
       javaCore, javaJdbc, javaEbean
    )

    val main = play.Project(appName, appVersion, appDependencies).settings(
      // Add your own project settings here      
    )

}

プロジェクトの mainLang パラメータはもう必要なくなりました。 Play 2.1 からは、プロジェクトのメイン言語は追加されたモジュールによって自動的に決定されます。具体的には、 javaCore モジュールが追加されていればメイン言語は JAVA となり、それ以外のケースでは SCALA となります。上記の Build.scala ファイルの例でいうと、 appDependencies の部分にモジュール依存性が書かれています。

§play.mvc.Controller.form() が play.data.Form.form() へ名称変更

Play のモジュール化に関連して、 play.data パッケージとその依存ライブラリはPlayのコアモジュールから分離して javaCore モジュールに移動しました。結果的に、 play.mvc.Controller#formplay.data.Form#form へ移動しています。

§play.db.ebean.Model.Finder.join() が fetch() へ名称変更

コード整理の一環として、 Finder API の join メソッドが fetch メソッドに置き換えられました。機能には変更ありません。

§Play の Promise から、Scala の Future への移行

Scala 2.10 で scala.concurrent.Future が導入されたことで、Scala のエコシステムに散在していた様々な Future 、 Promise ライブラリが統合され始めました。

Play が scala.concurrent.Future を利用するということは、つまり開発者が Play の内部 API および外部ライブラリ両方の Future/Promise をそのまま組み合わせられるようになったということです。

今のところ、Java ユーザは引き続き scala.concurrent.Future をラップした Play の Promise を利用することが想定されています

次のコードスニペットを見てみましょう。

import play.api.libs.iteratee._
import play.api.libs.concurrent._
import akka.util.duration._

def stream = Action {
    AsyncResult {
      implicit val timeout = Timeout(5.seconds)
      val akkaFuture =  (ChatRoomActor.ref ? (Join()) ).mapTo[Enumerator[String]]
      //convert to play promise before sending the response
      akkaFuture.asPromise.map { chunks =>
        Ok.stream(chunks &> Comet( callback = "parent.message"))
      }
    }
  }
  

新しい scala.concurrent.Future を利用すると、このコードは次のように変わります。

import play.api.libs.iteratee._
import play.api.libs.concurrent._
import play.api.libs.concurrent.Execution.Implicits._

import scala.concurrent.duration._

  def stream = Action {
    AsyncResult {
      implicit val timeout = Timeout(5.seconds)
      val scalaFuture = (ChatRoomActor.ref ? (Join()) ).mapTo[Enumerator[String]]
      scalaFuture.map { chunks =>
        Ok.stream(chunks &> Comet( callback = "parent.message"))
      }
    }
  }

インポートについての変更は次の通りです。

一般的に言うと、 “error: could not find implicit value for parameter executor” というエラーが出た場合、以下のインポートが足りない可能性があります。

import play.api.libs.concurrent.Execution.Implicits._

(詳細については Scalaの実行コンテキストに関するドキュメント を参照してください)

最後に、次の二点を改めて確認しましょう。

§Scala JSON API への変更

Play 2.1で は、全く新しい Scala 向けの JSON のバリデータとパスナビゲータ API が導入されました。この API は既存の JSON パーサとは互換性がありません。

play.api.libs.json.Reads型のシグネチャも変更されました。次のコードを見てください。

trait play.api.libs.json.Reads[A] {
  self =>

  def reads(jsValue: JsValue): A

}

このコードは、 Play 2.1 では次のように変わりました。

trait play.api.libs.json.Reads[A] {
  self =>

  def reads(jsValue: JsValue): JsResult[A]

}

例えば、 Play 2.0User 型の JSON シリアライザは次のように実装していました。

implicit object UserFormat extends Format[User] {

  def writes(o: User): JsValue = JsObject(
    List("id" -> JsNumber(o.id),
      "name" -> JsString(o.name),
      "favThings" -> JsArray(o.favThings.map(JsString(_)))
    )
  )

  def reads(json: JsValue): User = User(
    (json \ "id").as[Long],
    (json \ "name").as[String],
    (json \ "favThings").as[List[String]]
  )

}

これを Play 2.1 では次のようにリファクタリングする必要があります。

implicit object UserFormat extends Format[User] {

  def writes(o: User): JsValue = JsObject(
    List("id" -> JsNumber(o.id),
      "name" -> JsString(o.name),
      "favThings" -> JsArray(o.favThings.map(JsString(_)))
    )   
  )   

  def reads(json: JsValue): JsResult[User] = JsSuccess(User(
    (json \ "id").as[Long],
    (json \ "name").as[String],
    (json \ "favThings").as[List[String]]
  ))  

}

JSON を生成する API も同様に進化しました。次のコードを見てください。

val jsonObject = Json.toJson(
  Map(
    "users" -> Seq(
      toJson(
        Map(
          "name" -> toJson("Bob"),
          "age" -> toJson(31),
          "email" -> toJson("[email protected]")
        )
      ),
      toJson(
        Map(
          "name" -> toJson("Kiki"),
          "age" -> toJson(25),
          "email" -> JsNull
        )
      )
    )
  )
)

これを Play 2.1 で書くと次のようになります。

val jsonObject = Json.obj(
  "users" -> Json.arr(
    Json.obj(
      "name" -> "Bob",
      "age" -> 31,
      "email" -> "[email protected]"
    ),
    Json.obj(
      "name" -> "Kiki",
      "age" -> 25,
      "email" -> JsNull
    )
  )
)

これら機能の詳細については JSON関連のドキュメント を参照してください。

Cookie を永続化するためにはこれまで maxAge に -1 を設定していました。しかし、 JBoss Netty 側の変更により、これからは -1 の代わりに null または None (利用する API に依ります)を設定するようになりました。 maxAge に 0 以下の値を設定した場合、Cookie は直ちに期限切れします。

SimpleResultdiscardingCookies(String\*) (Scala) と discardCookies(String…) (Java) メソッドは特定のパスやドメインにセットされた Cookie や、セキュア Cookie を扱えなかったため、非推奨になりました。代わりに、discardingCookies(DiscardingCookie*) (Scala) と discardCookie (Java) メソッドを利用してください。

§RequireJS

Play 2.0 では JavaScript は Google Closure の CommonJS モジュールサポートによって処理されていました。 Play 2.1 からは代わりに RequireJS が使われるようになりました。

実利用においてこれが意味するのは、特に何か設定しない限り、 Play は stage 、 dist 、 start 時のみ JavaScript を minify するということです。開発モード時は、クライアント側で JavaScript モジュール間の依存性が解決されます。

この機能を利用する場合は、 project/Build.scala 内の設定に RequireJS で管理したいモジュールを追加する必要があります。

requireJs := "main.js"

この機能の詳細については RequireJS関連のドキュメント を参照してください。