Magnolia Tech

いつもコードのことばかり考えている人のために。

Json4sのJSON ASTからScalaのオブジェクトを生成する

次は、Json4sのJSON ASTからScalaのオブジェクトを生成する方法について解説。

Play-JSONでのScalaオブジェクト生成

Json4sのオブジェクト生成の前に、Play-JSONにおけるオブジェクト生成方法について見てみます。

import play.api.libs.json._
import play.api.libs.json.Reads._

case class Person(name: String, age: Int)

object Main {
  def main(args: Array[String]): Unit = {

    implicit val PersonFormat = Json.format[Person]

    val source = """{ "name": "John", "age": 42 }"""
    val jsonAst = Json.parse(source)

    val result = jsonAst.validate[Person]

    result match {
      case s: JsSuccess[Person] => {
        val person: Person = s.get
        println(person)
      }
      case e: JsError => println(e) # prints 'Person(John,42)'
    }
  }
}

ポイントは、implicit val PersonFormat = Json.format[Person]という指定です。Play-JSONでは、case classのオブジェクトを生成するために、このような指定が必要になります。

Json4sでのScalaオブジェクト生成

では同じようにJson4sでオブジェクトを生成してみる。

import org.json4s._
import org.json4s.jackson.JsonMethods._

case class Person(name: String, age: Int)

object Main {
  def main(args: Array[String]): Unit = {
    implicit val formats = DefaultFormats

    val source = """{ "name": "John", "age": 42 }"""
    val jsonAst = parse(source)

    val result = jsonAst.extract[Person]

    println(result) # prints 'Person(John,42)'
  }
}

少し形式を変えて、case classではなく、通常のクラスとして定義してみます。

import org.json4s._
import org.json4s.jackson.JsonMethods._

class Person(val name: String, val age: Int)

object Main {
  def main(args: Array[String]): Unit = {
    implicit val formats = DefaultFormats

    val source = """{ "name": "John", "age": 42 }"""
    val jsonAst = parse(source)

    val result = jsonAst.extract[Person]

    println(result.name) # prints "John"
    println(result.age) # prints "42"
  }
}

unapplyメソッドが無いので、個別に出力していますが、case classでなくてもオブジェクトが得られていることが分かると思います。

一方で、Play-JSONでは通常のクラスに変更するとコンパイルエラーになります。No apply function found for example.Personと、No Json deserializer found for type example.Person. Try to implement an implicit Reads or Format for this type.というエラーが出ます。

これは他のScala用のJSONライブラリでも同様で、case classの場合は、コンパニオンオブジェクトを渡したり、予め利用するcase classの型を登録しておいたり、通常のクラスであれば、自前で変換方法を詳細に定義する必要があります。

しかし、Json4sではどれも必要ありません。

なぜでしょうか?

というところで次回に続きます。