Circe解码用户列表失败但单个用户正常的问题排查
问题:Circe解码User列表失败,单个User正常
我编写了两个测试用例:解码单个User的测试可正常运行,但解码User列表的测试却失败了。
测试代码如下:
import User._ import io.circe._ import io.circe.syntax._ import io.circe.parser.decode class UserSuite extends munit.FunSuite: test("List of users can be decoded") { val json = """|{ | "data" : [ | { | "id" : "someId", | "name" : "someName", | "username" : "someusername" | }, | { | "id" : "someId", | "name" : "someName", | "username" : "someusername" | } | ] |}""".stripMargin println(decode[List[User]](json)) } test("user can be decoded") { val json = """|{ | "data" : { | "id" : "someId", | "name" : "someName", | "username" : "someusername" | } |}""".stripMargin println(decode[User](json)) }
失败的测试输出:
Left(DecodingFailure(List, List(DownField(data))))
我的Decoder定义如下:
final case class User( id: String, name: String, username: String ) object User: given Decoder[List[User]] = deriveDecoder[List[User]].prepare(_.downField("data")) given Decoder[User] = deriveDecoder[User].prepare(_.downField("data"))
环境为Scala 3.2.0和circe 0.14.1,请问这是Circe的Bug还是我的写法有误?
解答
这不是Circe的Bug,是你的写法有误。问题出在List[User]的解码器定义上:
deriveDecoder是Circe用来推导case class或产品类型解码器的工具,而List是容器类型,Circe已经内置了它的解码器实现,不需要(也不能)用deriveDecoder来生成。- 你写的
deriveDecoder[List[User]]会生成一个错误的解码器,它试图把JSON内容当作一个case class来解析,而非列表,这就导致了解码失败。
修正方案
把List[User]的解码器定义改成直接使用Circe内置的Decoder[List[User]],再结合prepare定位到data字段:
final case class User( id: String, name: String, username: String ) object User: given Decoder[User] = deriveDecoder[User].prepare(_.downField("data")) // 修正List[User]的解码器 given Decoder[List[User]] = Decoder[List[User]].prepare(_.downField("data"))
或者更直观的写法,用Decoder.instance明确指定解码逻辑:
given Decoder[List[User]] = Decoder.instance { cursor => cursor.downField("data").as[List[User]] }
为什么单个User的解码正常?
因为User是case class,deriveDecoder[User]能正确生成它的解码器,再通过prepare(_.downField("data"))定位到嵌套的data字段,逻辑完全正确,所以解码成功。
内容的提问来源于stack exchange,提问作者TomPoczos
相关产品推荐
相关产品推荐

