KZKY memo

自分用メモ.

Scala Json4s

ooyalaの記事だと,json4sを推奨していた.
パフォーマンス比較もしている.

json4s

jacksonとnative(pure scala)がある.
json4s-jacksonを使う.

Producing Json

基本的に
(key -> value) ~ (key -> value)
のように,kvのペアを結合していく

ProcudeJsonSample.scala

package edu.kzk.io.json4s

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

object ProcudeJsonSample extends App {
  case class Winner(id: Long, numbers: List[Int])
  case class Lotto(id: Long, winningNumbers: List[Int], winners: List[Winner], drawDate: Option[java.util.Date])

  val winners = List(Winner(23, List(2, 45, 34, 23, 3, 5)), Winner(54, List(52, 3, 12, 11, 18, 22)))
  val lotto = Lotto(5, List(2, 45, 34, 23, 7, 5, 3), winners, None)

  val json =
    ("lotto-id" -> lotto.id) ~
      ("winning-numbers" -> lotto.winningNumbers) ~
      ("draw-date" -> lotto.drawDate.map(_.toString)) ~
      ("winners" ->
        lotto.winners.map { w =>
          (("winner-id" -> w.id) ~
            ("numbers" -> w.numbers))
        })

  println(compact(render(json)))
}

Quering json (LINQ-style)

LINQ-styleでjson objectに対してクエリを投げる.

LINQSample.scala

package edu.kzk.io.json4s

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

object LINQSample extends App {
  // json value
  val jvalue = parse("""
         { "name": "joe",
           "age": 33,
           "children": [
             {
               "name": "Mary",
               "age": 5
             },
             {
               "name": "Mazy",
               "age": 3
             }
           ]
         }
       """)

  println(pretty(render(jvalue)))

  val value = jvalue.values;
  println(value)

  // LINQ-style
  val queryResults = for {
    JObject(child) <- jvalue
    JField("age", JInt(age)) <- child
  } yield age

  println(queryResults)

}

Querying json (XPath)

Xpath-likeにjsonにクエリを投げる.

GitHubのサンプルだと,\, \\が定義されてないので使えないとEclipseに怒られる.
型が(String, JObject)になっており,その原因は(xxx -> yyy)で,jsonのトップレベルがmapで認識されているから.
なので,renderしてJValueにしている.

package edu.kzk.io.json4s

object XpathSample extends App {
  import org.json4s._
  import org.json4s.JsonDSL._
  import org.json4s.jackson.JsonMethods._
  import com.fasterxml.jackson.annotation.JsonValue

  // json value
  val jvalue = render(
    ("person" ->
      ("name" -> "Joe") ~
      ("age" -> 35) ~
      ("spouse" ->
        ("person" ->
          ("name" -> "Marilyn") ~
          ("age" -> 33)
        )
      )
    ))

  // \\ sample
  var extractedJsonValue = jvalue \\ "spouse";
  println(compact(extractedJsonValue))

  // \\ concatenation sample
  extractedJsonValue = jvalue \\ "spouse" \\ "person" \\ "age"
  println(compact(extractedJsonValue))

  // findField sample
  val jField = jvalue findField {
    case JField("name", _) => true
    case _ => false
  }
  println(jField.get._2.values) // unboxed value

  // filterField sample
  val jFilterFields = jvalue filterField {
    case JField("name", _) => true
    case _ => false
  }
  println(jFilterFields)
}

Extracting value

Jsonからデータを抜き出して,対応するあるクラスのオブジェクトをつくる.

  • case classを作る
case class Child(name: String, age: Int, birthdate: Option[java.util.Date])
case class Address(street: String, city: String)
case class Person(name: String, address: Address, children: List[Child])
  • parseでJValueを作る
val jvalue = parse("""
...
"""
  • extract
val person = jvalue.extract[Person]

nullの可能性のあるフィールドはOptionをつけること

ExtractAsCaseClassSample.scala

package edu.kzk.io.json4s

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

object ExtractAsCaseClassSample extends App {
  implicit val formats = DefaultFormats // Brings in default date formats etc.

  case class Child(name: String, age: Int, birthdate: Option[java.util.Date])
  case class Address(street: String, city: String)
  case class Person(name: String, address: Address, children: List[Child])

  // json value
  val jvalue = parse("""
         { "name": "joe",
           "address": {
             "street": "Bulevard",
             "city": "Helsinki"
           },
           "children": [
             {
               "name": "Mary",
               "age": 5,
               "birthdate": "2004-09-04T18:06:22Z"
             },
             {
               "name": "Mazy",
               "age": 3
             }
           ]
         }
       """)

  val person = jvalue.extract[Person]
  println(person)

  //  val address = json.extract[Address]
  //  println(address)

}