使用 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)
}
如果清晰度比性能更重要,这可能会获胜。
使用 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)
}
如果清晰度比性能更重要,这可能会获胜。