LoginSignup
8
9

More than 5 years have passed since last update.

Jackson を Scala らしく使う

Last updated at Posted at 2014-02-04

Scala 2.10 から追加された implicit class 使って、Jackson を Scala らしく書く。json4s 使うほどのことはやらないのでお手軽実装。

こんな感じで書けるようになる:

サンプル
  def main(args: Array[String]) = {

    val bar = Person("Bar Smith")
    val foo = Person("Foo Smith", Set(bar))

    // JSON 文字列にシリアライズ
    val fooJson = foo.toJsonString
    println(fooJson)
    // 出力: {"name":"Foo Smith","children":[{"name":"Bar Smith","children":[]}]}

    // JSON 文字列からデシリアライズ
    val parsed = """{"name":"Hoge","children":[]}""".asJsonStringOf[Person]
    println(parsed)
    // 出力: Person(Hoge,Set())
  }

  // なにか適当な bean っぽい変哲もないクラス
  case class Person(name: String, children: Set[Person] = Set())

上記のように書くには、下記のようなクラスを用意して、インポートすれば良い:

JacksonImplicits.scala
object JacksonImplicits {
  implicit class JsonString(json: String) {
    // FIXME メソッド名が変
    def asJsonStringOf[T](implicit m: Manifest[T], om: ObjectMapper): T =
      om.readValue(json, typeRef[T])
  }
  implicit class JsonSerializable(any: AnyRef)
                                 (implicit om: ObjectMapper) {
    def toJsonString: String = om.writeValueAsString(any)
  }

  private def typeRef[T](implicit m: Manifest[T]) =
    new TypeReference[T] {
      override def getType = typeFromClassManifest(m)
    }

  def typeFromClassManifest(m: Manifest[_]): Type = {
    if (m.typeArguments.isEmpty) m.runtimeClass
    else new ParameterizedType {
      def getRawType: Type = m.runtimeClass
      def getActualTypeArguments: Array[Type] =
        m.typeArguments.map(typeFromClassManifest).toArray
      def getOwnerType: Type = null
    }
  }
}

Scala 2.9 以前でも pimp my library パターン使えば数行編集するだけで動くはず。

Scala 書き始めて半月くらいだけど、どうもまだリフレクション周りが辛くて、typeRef 以降に半日以上かかって頑張った。

8
9
0

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
8
9