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

Scala/Play中如何将平级字段JSON转为带嵌套类的Case Class

解决Play JSON解析中嵌套Case Class的路径匹配问题

你的问题根源很明确:当前的Reads[Car]期望JSON里存在一个名为financialInfo的嵌套对象,但实际返回的JSON中,cost和down_payment是和其他字段同级的顶级属性,所以Play JSON找不到financialInfo路径,抛出了error.path.missing错误。

要解决这个问题,你只需要调整Car的Reads定义,直接从JSON的根路径读取cost和down_payment字段,用来构建FinancialInfo实例,而不是尝试读取不存在的子路径。

修改后的代码实现

import play.api.libs.functional.syntax._
import play.api.libs.json._

case class Car(
  make: String,
  model: String,
  year: Int,
  color: String,
  owner: String,
  maxSpeed: Int,
  wheelSize: Int,
  isConvertible: Boolean,
  license: String,
  financialInfo: FinancialInfo,
  otherProperty1: Int,
  otherProperty2: Int,
  otherProperty3: Int,
  otherProperty4: Int,
  otherProperty5: Int,
  otherProperty6: Int,
  otherProperty7: Int,
  otherProperty8: Int,
  otherProperty9: Int,
  otherProperty10: Int,
  otherProperty11: Int
)

object Car {
  implicit val reads: Reads[Car] = (
    (__ \ "make").read[String] and
    (__ \ "model").read[String] and
    (__ \ "year").read[Int] and
    (__ \ "color").read[String] and
    (__ \ "owner").read[String] and
    (__ \ "max_speed").read[Int] and
    (__ \ "wheel_size").read[Int] and
    (__ \ "is_convertible").read[Boolean] and
    (__ \ "license").read[String] and
    // 关键修改:直接从根路径读取cost和down_payment构建FinancialInfo
    ((__ \ "cost").read[BigDecimal] and (__ \ "down_payment").read[BigDecimal])(FinancialInfo.apply _) and
    (__ \ "other_property_1").read[Int] and
    (__ \ "other_property_2").read[Int] and
    (__ \ "other_property_3").read[Int] and
    (__ \ "other_property_4").read[Int] and
    (__ \ "other_property_5").read[Int] and
    (__ \ "other_property_6").read[Int] and
    (__ \ "other_property_7").read[Int] and
    (__ \ "other_property_8").read[Int] and
    (__ \ "other_property_9").read[Int] and
    (__ \ "other_property_10").read[Int] and
    (__ \ "other_property_11").read[Int]
  )(Car.apply _)
}

case class FinancialInfo(
  cost: BigDecimal,
  downPayment: BigDecimal
)

object FinancialInfo {
  // 保留原有的Reads定义,后续如果有需要解析嵌套的financialInfo对象时仍能复用
  implicit val reads: Reads[FinancialInfo] = (
    (__ \ "cost").read[BigDecimal] and
    (__ \ "down_payment").read[BigDecimal]
  )(FinancialInfo.apply _)
}

更简洁的复用方式

如果你想复用FinancialInfo.reads而不是重复编写读取逻辑,可以用Reads.at来指定读取路径为当前根路径:

// 在Car的reads中替换对应行
Reads.at(__)(FinancialInfo.reads)

这样代码会更简洁,而且保持了FinancialInfo的Reads定义的复用性。

验证修改效果

现在用你提供的JSON响应调用response.json.validate[List[Car]],就能成功将顶级的cost和down_payment字段映射到Car的financialInfo属性中,不会再出现路径缺失的错误。

内容的提问来源于stack exchange,提问作者ElGatoGabe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:27:19