Play:如何验证属性可能属于不同类型的JSON?

时间:2015-09-05 21:07:21

标签: json scala playframework

我需要一个包含名称/值对的JSON结构......值可能是StringList[String]

{
  "name":"id",
  "value":"55e9cf3e0100003700dd2134"
}

{
  "name":"id",
  "value":["55e9cf3e0100003700dd2134","55e9e3430100004000d73b59"]
}

下面是我用来处理这种结构的类:

class NameValue protected(protected var json: JsValue) {

  def name = json as (__ \ 'name).read[String]
  def name_= (v: String) = setValue((__ \ 'name), Json.toJson(v))
  def value = json \ "value" match {
    case v: JsString => v.value
    case v => v.as[List[String]].head
  }
  def value_= (v: String) = setValue((__ \ 'value), Json.toJson(v))
  def multiValue = json \ "value" match {
    case v: JsString => List(v.value)
    case v => v.as[List[String]]
  }
  def multiValue_= (v: List[String]) = setValue((__ \ 'value), Json.toJson(v))
} 

value方法返回

  1. String
  2. 的值 as-is
  3. List[String]
  4. 的第一个元素

    multiValue方法返回

    1. List[String]
    2. 的值 as-is
    3. List[String]
    4. 的情况下包含一个元素的String

      下面是创建NameValue个实例并验证其JSON的伴随对象:

      object NameValue {
      
        import play.api.libs.functional.syntax._
        import play.api.libs.json.Reads._
      
        def apply(json: JsValue): JsResult[NameValue] = {
          validateNameValue.reads(json).fold(
            valid = { validated => JsSuccess(new NameValue(validated)) },
            invalid = { errors => JsError(errors) }
          ) 
        } 
      
        def apply(name: String, value: String): NameValue = new NameValue(
          nameValueWrites.writes(name, Some(value), None) 
        )  
      
        def apply(name: String, multiValue: List[String]): NameValue = new NameValue(
          nameValueWrites.writes(name, None, Some(multiValue)) 
        )   
      
        def unapply(nameValue: NameValue) = {
          if (nameValue eq null) None
          else {
            val multiValue = rameValue.multiValue
            Some((
              nameValue.name,
              if (multiValue.length > 1) multiValue else multiValue.head
            ))
          }
        }
      
        implicit val nameValueFormat = new Format[NameValue] {
          def reads(json: JsValue) = NameValue(json)
          def writes(nameValue: NameValue) = nameValue.json
        }
      
        private val nameValueWrites = (
          (__ \ 'name).write[String] ~
          (__ \ 'value).writeNullable[String] ~
          (__ \ 'value).writeNullable[List[String]]
        ).tupled
      
        private val multiValue: Reads[JsArray] = {
          (__ \ 'value).json.pick[JsArray] andThen verifying[JsArray](_.value.nonEmpty)
        }
      
        val validateNameValue = (
          ((__ \ 'name).json.pickBranch) ~
          ((__ \ 'value).json.pickBranch)
        ).reduce
      
        // how do I integrate this in `validateNameValue`?
        val validateNameValue2 = (
          ((__ \ 'name).json.pickBranch) ~
          ((__ \ 'value).json.copyFrom(multiValue))
        ).reduce
      }
      

      一切正常......但无论value属性是String还是List[String],我都只想拥有一个验证器。如何创建一个替换validateNameValuevalidateNameValue2

      的验证器

1 个答案:

答案 0 :(得分:0)

将值区分为String并且String列表不是一个好习惯。 List也可以包含单个元素。

此外,您可以使用 Json.format 来删除为案例类定义读者和编写者的样板代码。

 import play.api.libs.json.Json

 object NameValue {
    implicit val format = Json.format[NameValue]
}