博多南ウェブサービスのblog

博多南ウェブサービスのサービス紹介

【Play Framework 2.8.x サンプル】JSON に case object を使いたい

Play Framework を始めたばかりの方向けに、サンプルを進めるうえで困ったところを共有する目的で書いています。

Play Framework 2.8.x にて、JSON に case object を使うときのメモです。

以下、目次

前提

こんな感じの case object を含んだ case class を、

sealed trait Color
case object Red    extends Color
case object Yellow extends Color
case object Green  extends Color

case class Origami(color: Color)

こんな感じの JSON でやりとりしたい

{
  "origami" : {
    "color" : "Red"
  }
}

方針

  • case object が増えたりしたときに、変更箇所が少ない or コンパイルエラーで変更すべき箇所を教えてくれる
  • case object のパターンマッチは残したい

結果

build.sbt

libraryDependencies += "com.beachape" %% "enumeratum" % "1.7.0",

こんな感じで、

  import enumeratum.EnumEntry
  import enumeratum.Enum

  sealed trait Color extends EnumEntry
  object Color extends Enum[Color] {
    case object Red    extends Color
    case object Yellow extends Color
    case object Green  extends Color
    lazy val values: IndexedSeq[Color] = findValues
  }

  import play.api.libs.json._

  implicit val colorWrites = new Writes[Color] {
    override def writes(color: Color): JsValue = Json.toJson(color.toString)
  }
  implicit val colorReads = new Reads[Color] {
    override def reads(json: JsValue): JsResult[Color] =
      json.asOpt[String].flatMap(Color.withNameOption(_)) match {
        case Some(color) => JsSuccess(color)
        case None        => JsError("cannot parse to Color.")
      }
  }

  case class Origami(color: Color)
  implicit val origamiFormat = Json.format[Origami]

こうなります。

scala> :paste
      val json: JsValue = Json.obj(
        "origami" -> Json.obj(
          "color" -> "Red"
        )
      )

val json: play.api.libs.json.JsValue = {"origami":{"color":"Red"}}

scala>  (json \ "origami").validate[Origami](origamiFormat).get
val res0: Origami = Origami(Red)

参考にしたところ

以上でした。