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

Scala中如何让JSON解析与错误处理更具函数式风格?

问题描述

待解析的JSON数据:

{"messageTypeId": 2, "messageId": "19223201", "BootNotification" : {"reason": "PowerUp", "chargingStation": {"serialNumber" : "12345", "model" : "", "vendorName" : "", "firmwareVersion" : "", "modem": {"iccid": "", "imsi": ""}}}}

现有Play JSON的Reads实现:

implicit val ocppCallRequestReads: Reads[OCPPCallRequest] = Reads { jsValue =>
    val messageTypeId = (jsValue \ 0).toOption
    val messageId = (jsValue \ 1).toOption
    val actionName = (jsValue \ 2).toOption
    val payload = (jsValue \ 3).toOption
    (messageTypeId.zip(messageId.zip(actionName.zip(payload)))) match {
      case Some(_) => JsSuccess(
        OCPPCallRequest( // Here I know all 4 exists, so safe to call head
          messageTypeId.head.as[Int],
          messageId.head.as[String],
          actionName.head.as[String],
          payload.head
        )
      )
      case None => JsError( // Here, I know that I have to send a CallError back!
        "ERROR OCCURRED" // TODO: Work on this!
      )
    }
  }

当前实现的错误处理只能返回笼统提示,无法给出具体错误信息,同时希望避免逐个检查Option来填充错误,如何改造成更具函数式风格的实现?


函数式风格实现方案

Play JSON内置了一套组合子API,可让你以函数式方式组合Reads逻辑,自动完成错误收集,无需手动操作Option。核心思路是将单个字段的读取逻辑通过组合子拼接,同时自动生成针对性的错误信息。

改造后的代码:

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

case class OCPPCallRequest(messageTypeId: Int, messageId: String, actionName: String, payload: JsValue)

implicit val ocppCallRequestReads: Reads[OCPPCallRequest] = (
  (__ \ 0).read[Int](Reads.min(0).orElse(Reads.max(3))).withMessage("messageTypeId必须是0-3之间的整数") and
  (__ \ 1).read[String].minLength(1).withMessage("messageId不能为空字符串") and
  (__ \ 2).read[String].minLength(1).withMessage("actionName不能为空字符串") and
  (__ \ 3).read[JsValue].withMessage("payload必须是有效的JSON值")
)(OCPPCallRequest.apply _)

核心优势:

  • 自动错误收集:Play JSON会自动汇总所有字段的错误(如类型不匹配、字段缺失、自定义约束不满足等),无需手动处理Option的空值判断。
  • 函数式组合:通过and等组合子将多个字段的读取逻辑拼接成完整的Reads,代码简洁且可读性强。
  • 精准错误提示:通过withMessage为每个字段添加针对性错误信息,方便定位问题。
  • 类型安全:所有类型转换由Play JSON处理,避免手动调用as[T]带来的运行时异常。

错误处理说明:

当解析失败时,JsError会包含所有失败字段的具体错误信息,例如:

  • 若messageTypeId缺失或超出0-3范围,会返回"messageTypeId必须是0-3之间的整数"及对应路径信息;
  • 若messageId为空字符串,会返回"messageId不能为空字符串"的提示。

你可以通过JsError.toJson将错误信息转为JSON格式,直接作为CallError的响应内容返回。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 04:35:32