json - Scala Play 2.6:使用字段之间的约束解析 json
问题描述
我想在解析 json 时根据另一个字段的值来验证一个字段。
例如,当我读取一个范围时,我想验证 min < max:
import org.scalatest.{FlatSpec, Matchers}
import play.api.libs.json.{JsError, Json, Reads}
class JsonReadsTest extends FlatSpec with Matchers {
"Json" should "be reads" in {
val reads: Reads[Range] = ???
val json = Json.obj("min" -> 3, "max" -> 2)
reads.reads(json) shouldBe JsError("max should be superior to min")
}
}
case class Range(min: Int, max: Int)
解决方案
直进式 oop 解决方案
您可以创建一个扩展 Reads[T] 的对象并直接实现 reads 方法而无需功能构建器(此方法未在文档中完全涵盖,但您可以在源代码中找到许多示例)
val reads1 = new Reads[Range] {
def reads(json: JsValue): JsResult[Range] = {
(for {
min <- (json \ "min").validate[Int]
max <- (json \ "max").validate[Int]
} yield (min, max)).flatMap {
case (min, max) if max > min =>
JsSuccess(Range(min, max))
case _ =>
JsError(Seq(JsPath ->
Seq(JsonValidationError("error.expected.range"))))
}
}
}
功能构建器解决方案
val reads2 = (
(__ \ "min").read[Int] and
(__ \ "max").read[Int]
).tupled
.filter(JsonValidationError("error.expected.range")){ case (min, max) => max > min}
.map{ case (min, max) => Range(min, max)}
最佳实践
您正在尝试混合阅读和验证,当您在不同模块中有不同的验证规则时,这可能会成为问题。有一种将 json 对象解析为演示模型类的做法,例如
case class RangeInput(min: Int, max: Int)
然后将其转换为执行验证的业务模型类
def validate(input: RangeInput): Option[Range] =
input.filter(i => i.max > i.min).map(i => Range(i.min, i.max))
如果您需要汇总验证错误,诸如猫验证之类的东西可以帮助您
推荐阅读
- mlr3 - 在 MLR3 Ranger 设置 class.weights 中,错误“'xs' 上的断言失败:class.weights:必须长度为 1”
- javascript - 错误:在 XMLHttpRequest.handleLoad (xhr.js:62) 的结算 (settle.js:17) 处的 createError (createError.js:16) 处请求失败,状态码为 404
- c++ - 在 C++ 中获取模板类型的“嵌套”模板参数的数量
- java - hamburgerMenu 无法使用硒
- reactjs - Reactjs:TypeError:无法读取未定义的属性“帖子”
- python - 无法使用预训练模型
- python - 如何从抓取的 html 页面(python)中生成(然后写入)xml 文件
- azure - 通过 Azure 应用程序代理的 SignalR 连接
- react-native - 检查滚动视图是否正在滚动
- java - Java执行shell命令,如何实时读取输出?