Scala学习小计 - 可以替代Play.api.json的JSON解析库 Circe

介绍

circe是另一个款独立的JSON处理库。首先它解决22字段和对象嵌套的问题。其次就是据说它很快。而且能自定义他的 decode 和 encode 隐式,来达到能处理一些个性化的cass class。

除此之外就是文档上介绍的一些常用的功能。官方文档

使用

首先如果想转换case class 也是需要定义隐式转换的。而且,它的一些自定义转换内容,都需要通过case class的object 去定义隐式来实现的。例如:

import io.circe._
import io.circe.generic.JsonCodec
import io.circe.generic.semiauto._
import io.circe.parser._
import io.circe.syntax._

case class EnA(
                name: String,
                age: Int,
                d: Option[Int],
                nickName: Option[String] = None
              )
              
object EnA {
  // 自身的默认解析和编译隐式
  implicit val decoder: Decoder[EnA] = deriveDecoder[EnA]
  implicit val encoder: Encoder[EnA] = deriveEncoder[EnA]

  // 如果case class作为 json 中 key 的时候,需要自定义一个字段作为key来解析
  implicit val keyEncoder = new KeyEncoder[EnA] {
    override def apply(en: EnA): String = en.name
  }
  // KeyDecoder同理
  
  // Encode和Decode也可以按照上面的去根据需要自定义
  implicit val encodeFoo: Encoder[Thing] = new Encoder[Thing] {
    final def apply(a: Thing): Json = Json.obj(
      ("foo", Json.fromString(a.foo)),
      ("bar", Json.fromInt(a.bar))
    )
  }
  implicit val decodeFoo: Decoder[Thing] = new Decoder[Thing] {
    final def apply(c: HCursor): Decoder.Result[Thing] =
      for {
        foo <- c.downField("foo").as[String]
        bar <- c.downField("bar").as[Int]
      } yield {
        new Thing(foo, bar)
      }
  }
}

转换json

// 一些预设的定义
val list1 = List(1, 2, 3)
val ena1 = EnA("小红", 22, Some(1))
val map1 = Map[String, Int]("map" -> 122)
val map2 = Map[Int, Int](1 -> 122)
val map3 = Map[EnA, Int](ena1 -> 122)
val json1 =
"""
  |{
  |  "foo": "bar",
  |  "baz": 123,
  |  "abc": { "abc2": 666 },
  |  "list of stuff": [ 4, 5, 6 ],
  |  "null field": null
  |}
""".stripMargin


// list/map/entity -> json object
val listJson = list1.asJson // 返回的Json
val mapJson = map1.asJson
val enaJson = ena1.asJson

// json string -> json object. 返回的是Either 
parse(json1) match {
  case Right(myJson) => // 转换成功
  case Left(msg) => // 转换失败
}

// json object -> list/map/entity...
enaJson.as[EnA] // 返回的是Either

// json object -> json string
listJson.noSpaces

// json string -> entity
decode[EnA](json)

提取json

// json 格式取数据需要用到“游标”来指示你想要的做什么,然后他去做。
val ena1Cursor = myJson.hcursor

// 获取嵌套多层结构 -> 结果是一个Either
println(
  ena1Cursor
    .downField("abc")
    .downField("abc2")
    .as[Int]
)
// 只适用于最后一层的 downField(k:String).as[E] 的缩写为 get[E](k:String)
println(ena1Cursor.get[io.circe.Json]("abc"))

改变json

// 处理某个字段值的变化 modify
println(
  ena1Cursor
    .downField("abc")
    .downField("abc2")
    .withFocus(_.mapNumber(a => a))
    .focus // 返回变化后的该字段 Option[Json]
)

// 重新设置字段内容 Json
println(
  ena1Cursor
    .downField("abc")
    .downField("abc2")
    .withFocus(_.withNumber(a =>
      Json.obj(
        ("new-Key", Json.fromInt(a.toInt.getOrElse(0) + 1))
      )
    ))
    .top // 返回整个变化后的json串 Option[Json]
)

注意的点:

  1. 在转换case class的时候,它不会受22个字段的限制,但是在字段类型是Option,值是None的时候,它会在json中展示该字段并且值是null
  2. play.api.json的只能将所有的key是字符串的转为json object,如果是其它类型会转换为json array类型。而circe会让你指定取哪个key并转换为字符串。

插件-注释转换

除以上之外,还可以使用注解的方式引入默认的隐式转换,但是需要额外的库paradise

build.sbt 中增加配置。

// 由于版本更新不及时,使用时,需要去github上看下版本对应关系。并使用与之对应的scala版本。
crossScalaVersions := Seq("2.12.8"),
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)

然后再定义case class的时候,我们可以直接使用注释来引入默认的转换规则

@JsonCodec
case class EnA(
                name: String,
                age: Int,
                d: Option[Int],
                nickName: Option[String] = None
              )

插件-Optics

默认的json取值过程比较繁琐且代码冗长。那么有一个新的插件库,为我们简化了该操作 – Optics。在官方的文档中有对其的介绍内容。

libraryDependencies += "io.circe" %% "circe-optics" % circeVersion

使用时,其主要就是将一个个游标的操作,通过一个顺序关系的定义预先定义出来。而后再去json中执行该预先定义的操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值