You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 10:01:01