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
相关产品推荐
相关产品推荐

