LoginSignup
22
20

More than 5 years have passed since last update.

circe触ってみた

Posted at

circeはJsonライブラリ。Argonautをforkしたもので、CatsやShapelessを使っている。Jawnという速いJsonパーサを使っているとのこと。

Argonautは触ったことないので比較してない。(・ω・`)

Encode

import io.circe._
import io.circe.syntax._
import io.circe.generic.auto._

scala> case class User(id: Int, name: String)
//defined class User

scala> User(1, "taro").asJson
//res79: io.circe.Json =
//{
//  "id" : 1,
//  "name" : "taro"
//}

なうい(・ω・`)

もう少し複雑に。

scala> case class Group(users: Seq[User], name: Option[String])
//defined class Group

scala> Group(Seq(User(1, "taro"), User(2, "sato")), Some("fuga")).asJson
//res84: io.circe.Json =
//{
//  "users" : [
//    {
//      "id" : 1,
//      "name" : "taro"
//    },
//    {
//      "id" : 2,
//      "name" : "sato"
//    }
//  ],
//  "name" : "fuga"
//}

Encoderの型クラスのインスタンスを定義すれば自動導出時に使ってくれる。DateTime系のインスタンスとか必要になりそう。

Decode

パースしてUserに詰める。

scala> parser.decode[User]("""{"id":1, "name":"taro"}""")
//res95: cats.data.Xor[io.circe.Error,User] = Right(User(1,taro))

失敗時。

scala> parser.decode[User]("""{"id":1, "name_fuga":"taro"}""")
//res96: cats.data.Xor[io.circe.Error,User] = Left(io.circe.DecodingFailure: Attempt to decode value on failed cursor: El(DownField(name),false))

XorはEitherみたいなもの。

Cursor

jsonを走査したりset/deleteしたりできる。
移動してidの値を取ってみる。

scala> val userJson: Json = User(1, "taro").asJson

scala> userJson.hcursor.get[Int]("id")
//res21: io.circe.Decoder.Result[Int] = Right(1)

配列から最初のオブジェクト取得。

scala> val groupJson = Group(Seq(User(1, "taro"), User(2, "sato")), Some("fuga")).asJson
//groupJson: io.circe.Json =
//{
//  "users" : [
//    {
//      "id" : 1,
//      "name" : "taro"
//    },
//    {
//      "id" : 2,
//      "name" : "sato"
//    }
//  ],
//  "name" : "fuga"
//}

scala> .hcursor.downField("users").downArray.first.as[User]
//res23: io.circe.Decoder.Result[User] = Right(User(1,taro))

hcursorのhはhistoryで操作履歴を持っているようだ。
履歴から再現したりできるもよう。

scala> val histories = groupJson.hcursor.downField("users").downArray.first.any.history
//histories: List[io.circe.HistoryOp] = List(El(MoveFirst,true), El(DownArray,true), El(DownField(users),true))

scala> groupJson.cursor.replay(histories).map(_.as[User])
//res26: Option[io.circe.Decoder.Result[User]] = Some(Right(User(1,taro)))

使いどころ難しそう(・ω・`)

Incomplete

decodeするとき、値が全部なくても後で渡すことができる。

普通にdecodeするとidがないのでエラー。

scala> parser.decode[User]("""{"name":"taro"}""")
//res98: cats.data.Xor[io.circe.Error,User] = Left(io.circe.DecodingFailure: Attempt to decode value on failed cursor: El(DownField(id),false))

idは後から渡すことに。

scala> parser.decode[Int => User]("""{"name":"taro"}""")
//res99: cats.data.Xor[io.circe.Error,Int => User] = Right(<function1>)

scala> .map(_(1))
//res100: cats.data.Xor[io.circe.Error,User] = Right(User(1,taro))

idという名前でちゃんと書きたいときは、

scala> import shapeless.Witness
//import shapeless.Witness

scala> import shapeless.labelled.{FieldType, field}
//import shapeless.labelled.{FieldType, field}

scala> parser.decode[FieldType[Witness.`'id`.T, Int] => User]("""{"name":"taro"}""")
//res105: cats.data.Xor[io.circe.Error,shapeless.labelled.FieldType[Symbol with shapeless.tag.Tagged[String("id")],Int] => User] = Right(<function1>)

scala> .map(_(field(1)))
//res106: cats.data.Xor[io.circe.Error,User] = Right(User(1,taro))

よさげ(・ω・`)

22
20
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
22
20