使用 Scala Play 读取 JSON 时出现未知字段时如何抛出错误?

How do I throw an error when an unknown field is present whilst reading JSON with Scala Play?

使用 JSON 模式,如果您希望模式在发现任何其他字段时验证失败,您可以在模式上抛出一个 "additionalProperties": false 并称之为一天,有点像这样:

{
    "$schema": "http://json-schema.org/draft-07/schema",
    "type": "object",
    "title": "",
    "description": "",
    "properties": {
        "fieldOne": {
            "type": "string",
            "description": "Example String"
        }
    },
    "additionalProperties": false
}

但是,如果我有以下情况class/object:

case class MyThing(fieldOne: Option[String])

object MyThing {
  implicit val reads: Reads[MyThing] = Json.reads[MyThing]
}

并向其提供 fieldOne 以外的内容,它仍会正确读取 class 中的 JSON,但 class 中的 class 将为空。

当从 JSON 读取到案例 class 时,在 JSON 中提供附加字段时是否有错误的方法?

Play JSON 本身没有这个,但在自定义 Reads 中,您可以从简单解析访问 JsValue/JsObject。所以对于一些简单的事情,你可以这样做:

object MyThing {
  // Single-abstract method should work, if not more explicitly extend Reads
  implicit val reads: Reads[MyThing] = { json: JsValue =>
    json match {
      case JsObject(kv) =>
        val keys = kv.keySet
        if (keys != expectedFields) {
          (keys -- expected).headOption.map { unexpected =>
            JsError(s"Encountered unexpected field $unexpected")
          }.getOrElse(JsError("Must be a non-empty object"))
        } else derivedReads.reads(json)
      case _ => JsError(JsonValidationError("must be an object"))
    }
  }

  private val expectedFields = Set("fieldOne")
  private val derivedReads = Json.reads[MyThing]
}

一般来说,假设您有一个对应的 Writes 服从往返 属性,您可以执行以下操作:

def strictify[T](reads: Reads[T], writes: Writes[T]): Reads[T] = new Reads[T] {
  def reads(json: JsValue): JsResult =
    reads.reads(json).filter { t =>
      val writeback = writes.writes(t)
      writeback == json
    }
}

这严格来说比签入自定义 Reads 效率低,但它确实启用了

object MyThing {
  implicit val writes: Writes[MyThing] = Json.writes[MyThing]
  implicit val reads: Reads[MyThing] = strictify(Json.reads[MyThing], writes)
}

如果清晰度比性能更重要,这可能会获胜。