Circe技术问询:数组元素转Case Class及相关优化问题
处理Circe JSON层级解析的两个问题
问题背景
现有如下JSON结构及初始Circe代码:
import io.circe._ import io.circe.parser._ val jStr = """ { "a1": ["c1", "c2"], "a2": [{"d1": "abc", "d2": "efg"}, {"d1": "hij", "d2": "klm"}] } """ val j = parse(jStr).getOrElse(Json.Null) val ja = j.hcursor.downField("a2").as[Json].getOrElse("").toString // 初始Song类及解码器 case class Song(id: String, title: String) implicit val songDecoder: Decoder[Song] = (c: HCursor ) => for { id <- c.downField("d1").as[String] title <- c.downField("d2").as[String] } yield Song(id,title) // 不合理的转String解码方式 io.circe.parser.decode[List[Song]](ja).getOrElse("")
问题1:将a1数组的c1值添加到每个Song实例中
需修改Song类为:case class Song(id: String, title: String, artist: String),把原JSON中a1数组的第一个元素(c1)作为每个Song的artist字段值。
解决方案
先从根JSON中提取a1的第一个元素,再结合该值解码a2列表并构造Song实例:
// 修改后的Song类 case class Song(id: String, title: String, artist: String) val rootJson = parse(jStr).getOrElse(Json.Null) val rootCursor = rootJson.hcursor // 提取a1数组的第一个元素,默认值可根据业务调整 val targetArtist = rootCursor.downField("a1") .as[List[String]] .map(_.headOption.getOrElse("unknown_artist")) .getOrElse("unknown_artist") // 直接从cursor解码a2,注入artist值 val songs = rootCursor.downField("a2") .as[List[Song]] { Decoder.decodeList { c: HCursor => for { id <- c.downField("d1").as[String] title <- c.downField("d2").as[String] } yield Song(id, title, targetArtist) } } .getOrElse(Nil)
或者用更优雅的参数化解码器方式:
// 定义带artist参数的解码器 def songDecoder(artist: String): Decoder[Song] = Decoder.forProduct3("d1", "d2", _ => artist)(Song) val songsAlt = for { a1List <- rootCursor.downField("a1").as[List[String]] artist = a1List.headOption.getOrElse("unknown_artist") songList <- rootCursor.downField("a2").as[List[Song]](Decoder.decodeList(songDecoder(artist))) } yield songList
问题2:移除转String的不合理解码方式
之前将a2的Json转为String再解码的方式完全多余,直接通过HCursor操作即可完成解码,无需中间字符串转换。
解决方案
直接使用根HCursor定位到a2字段,调用as[List[...]]完成解码:
// 以初始Song类为例,直接解码 val directSongs = rootCursor.downField("a2") .as[List[Song]] .getOrElse(Nil)
结合问题1的场景,同样不需要转String,直接在cursor层面完成所有解码逻辑,既高效又避免了字符串转换带来的潜在问题。
内容的提问来源于stack exchange,提问作者Lars Skaug
相关产品推荐
相关产品推荐

