Scala 3.2.2中ZIO-JSON使用case class默认值解码失败问题排查
问题
我编写了一个测试程序,当JSON字符串中缺少personId字段时,ZIO-JSON解码失败。但我已根据ZIO官方文档在case class中为personId设置了默认值。使用版本:Scala 3.2.2、ZIO 2.0.13、ZIO-JSON 0.5.0,相关代码及错误输出如下:
import zio.* import zio.json.* import zio.schema.{DeriveSchema, Schema} final case class Person(personId: Long = 1, name: String, age: Int) object Person { implicit val decoder: JsonDecoder[Person] = DeriveJsonDecoder.gen[Person] } object MyApp extends ZIOAppDefault { override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { _ <- Console.printLine("Decoding a JSON string representing a person...") jsonString = """ { "name": "John", "age": 30 } """.stripMargin result <- ZIO.fromEither(jsonString.fromJson[Person]) _ <- Console.printLine(s"Decoded Person: $result") } yield ExitCode.success }
输出:
Decoding a JSON string representing a person... timestamp=2023-11-02T21:11:01.198368Z level=ERROR thread=#zio-fiber-1 message="" cause="Exception in thread "zio-fiber-4" java.lang.String: .personId(missing) at <empty>.MyApp.run(MyApp2.scala:25) at <empty>.MyApp.run(MyApp2.scala:27)" Process finished with exit code 1
版本信息:
val zioVersion = "2.0.13" val zioJsonVersion = "0.5.0" scala version 3.2.2
解决方案
问题核心是ZIO-JSON的默认派生解码器DeriveJsonDecoder.gen不会自动识别case class的参数默认值,它会要求JSON中必须包含所有字段,哪怕字段定义了默认值。
要解决这个问题,需要修改解码器的生成方式:
- 使用
DeriveJsonDecoder.withDefaultValues.gen替代DeriveJsonDecoder.gen,该方法生成的解码器会在字段缺失时自动使用case class参数的默认值。 - 可选但推荐:给带默认值的字段添加
@jsonField注解,确保字段名与JSON键的映射准确,避免潜在的命名问题。
修改后的完整代码:
import zio.* import zio.json.* import zio.schema.{DeriveSchema, Schema} final case class Person(@jsonField("personId") personId: Long = 1, name: String, age: Int) object Person { // 生成支持默认值填充的解码器 implicit val decoder: JsonDecoder[Person] = DeriveJsonDecoder.withDefaultValues.gen[Person] } object MyApp extends ZIOAppDefault { override def run: ZIO[Environment with ZIOAppArgs, Any, Any] = for { _ <- Console.printLine("Decoding a JSON string representing a person...") jsonString = """ { "name": "John", "age": 30 } """.stripMargin result <- ZIO.fromEither(jsonString.fromJson[Person]) _ <- Console.printLine(s"Decoded Person: $result") } yield ExitCode.success }
运行修改后的代码,解码会成功,输出如下:
Decoding a JSON string representing a person... Decoded Person: Person(1,John,30)
内容的提问来源于stack exchange,提问作者Jimmy
相关产品推荐
相关产品推荐

