LoginSignup
6
6

More than 5 years have passed since last update.

Spray:引数が1つのクラスはJSON文字列に変換したい

Last updated at Posted at 2014-06-30

コンストラクタの引数がひとつしかないcase classをJSONに変換するとき、{"key": "value"} という形ではなく、ストレートに "value" という形に整形したい。

spray-jsonの jsonFormat1 関数を使うと前者になってしまう。次の例は、苗字と名前で氏名を構成する概念的な統一体(conceptual whole)についてのコードだ。このコードでは苗字と名前それぞれを jsonFormat1 を用いてJSONを変換している。

case class FirstName(firstName: String)
case class LastName(lastName: String)
case class Name(first: FirstName, last: LastName)

import spray.json.DefaultJsonProtocol

object NameJsonProtocol extends DefaultJsonProtocol {
  implicit val FirstNameFormat = jsonFormat1(FirstName)
  implicit val LastNameFormat = jsonFormat1(LastName)
  implicit val NameFormat = jsonFormat2(Name)
}

import spray.json._
import NameJsonProtocol._

println(Name(FirstName("Alice"), LastName("Brown")).toJson)

出力結果が冗長的になってしまう。firstやlastが2度出てくるためバイト数が増える。
加えて、ネストしているのでJSONをデコードするクライアント実装にも負担になる。

{"first":{"firstName":"Alice"},"last":{"lastName":"Brown"}}

理想的にはネストがなく冗長的でないJSONになってほしい。たとえばこのような:

{"first":"Alice","last":"Brown"}

これを実現するコードはこうなる:

case class FirstName(firstName: String)
case class LastName(lastName: String)
case class Name(first: FirstName, last: LastName)

import spray.json.{ JsString, JsValue, RootJsonFormat, DefaultJsonProtocol }

object NameJsonProtocol extends DefaultJsonProtocol {
  // map case classes with 1 string parameter to JSON string
  def jsonString[A](construct: (String) => A)(stringify: A => String): RootJsonFormat[A] = new RootJsonFormat[A] {
    def write(x: A): JsString = JsString(stringify(x))
    def read(json: JsValue): A = json match {
      case JsString(x) => construct(x)
      case x           => deserializationError("Expected JsString, but got " + x)
    }
  }

  implicit val FirstNameFormat = jsonString(FirstName)(_.firstName)
  implicit val LastNameFormat = jsonString(LastName)(_.lastName)
  implicit val NameFormat = jsonFormat2(Name)
}

import spray.json._
import NameJsonProtocol._

println(Name(FirstName("Alice"), LastName("Brown")).toJson)
6
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6