在没有 JSPath 的 Play 框架中验证 JSON

Validate JSON in Play framework without JSPath

我已经预先定义了 class MyClass 以下 JSON 结构:

{
  "key1": [
      // Objects of MyClass
  ],

  "key2": [
      // Objects of MyClass
  ],

  "key3": [
      // Objects of MyClass
  ]
}

key1, key2, key3 是可选的(至少有一个必须存在,但我不需要验证它) 根据 Play 框架文档,我需要执行以下操作:

implicit val myClassReads: Reads[] = (
  (JsPath \ "key1").read[List[MyClass]] and
  (JsPath \ "key2").read[List[MyClass]] and
  (JsPath \ "key3").read[List[MyClass]]
)

但是这种方法有一些缺点:

  1. key1, key2, key3的数据类型总是MyClass)。重复 read[MyClass] 似乎多余。

  2. 如果 JSON 架构发生变化而有 key1, key2, ... key100 怎么办?代码变得很乱

如何编写将 read[MyClass] 应用于所有字段的自定义验证器?

是这样的吗?

 def convertJsonToListModel[T](json: JsValue)(implicit reads: Reads[T]): List[T] = {
      val conversionResult: JsResult[List[T]] = json.validate[List[T]]
      conversionResult match {
        case s: JsSuccess[List[T]] => s.get
        case e: JsError => e.get
      }
 }

Play JSON 具有针对产品类型(例如案例 类)的自动格式推导。 您可以在文档中找到更多详细信息:https://www.playframework.com/documentation/latest/ScalaJsonAutomated 我想在你的情况下,这会像下一个:

import play.api.libs.json._

case class MyClass(value: String)

object MyClass {
 implicit format =  Json.format[Resident]
}

case class MyClassContainer(key1: List[MyClass], key2: List[MyClass], key3: List[MyClass])

object MyClassContainer {
 implicit format =  Json.format[MyClassContainer]
}

希望这会有所帮助。

如果您正在使用 Play Json 2.8.x,您可以这样做:

val result = json.validate[Map[String, List[MyClass]]]

Is it possible to validate whether the JSON keys are in ALLOWED_KEYS: List[String] with your approach?

您也可以使用另一种类型作为 Map 的键,只要您为该类型定义一个 KeyReads 实例即可。所以你可以使用一个枚举,只有有限数量的可能值。或者您可以使用优化类型(例如使用 "refined" 库)等等。

限制键的可能值的最简单方法是检查转换后的结果映射:

val ALLOWED_KEYS = Set("key1", "key2", ...)

val result = json.validate(
  Reads.verifying[Map[String, List[MyClass]]](_.keySet.subsetOf(ALLOWED_KEYS))
)

或者您也可以根据需要预先检查密钥:

val result = json.validate(
  Reads.verifying[JsObject](_.keys.subsetOf(ALLOWED_KEYS))
    .andThen(Reads.of[Map[String, List[MyClass]]])
)