用类型值验证json

时间:2018-10-02 10:01:27

标签: json scala

我要验证具有类型值的json 我有一个案例类SearchRequestMessage和一个带有json writer的伴随对象 值T可以是Long或UUID

case class SearchRequestMessage[T](jobId: UUID, offerId: UUID, search: T, searchByType: SearchByType)

object SearchRequestMessage{

  implicit def searchResultsWrites[T: Writes]: Writes[SearchRequestMessage[T]] = new Writes[SearchRequestMessage[T]] {
    def writes(searchSesult: SearchRequestMessage[T]) =
      JsObject(
        Seq(
          "jobId"  -> JsString(searchSesult.jobId.toString),
          "offerId"  -> JsString(searchSesult.offerId.toString),
          "search"  -> JsString(searchSesult.search.toString),
          "searchByType" -> JsString(searchSesult.searchByType.toString)
        ))
  }
}

我也有SearchByTypes枚举

object SearchByTypes extends Enumeration {

  type SearchByType = Value

  val Emails: SearchByType = Value(0, "EMAILS")
  val Offer: SearchByType  = Value(1, "OFFER")

  implicit val SearchByTypeFormat: Format[SearchByTypes.Value] = JsonFormatter.enumFormat(SearchByTypes)

}

枚举格式器

import play.api.libs.json._

object JsonFormatter {
  def enumFormat[T <: Enumeration](enum: T): Format[T#Value]        = new EnumFormatter[T](enum)
  def enumWithIdsFormat[T <: Enumeration](enum: T): Format[T#Value] = new EnumWithIdsFormatter[T](enum)

  class EnumFormatter[T <: Enumeration](enum: T) extends Format[T#Value] {
    override def writes(o: T#Value): JsValue = o match {
      case null => JsNull
      case _    => JsString(o.toString)
    }

    override def reads(json: JsValue): JsResult[T#Value] = json match {
      case JsString(value) => {
        try {
          JsSuccess(enum.withName(value))
        } catch {
          case _: NoSuchElementException =>
            JsError(
              s"Enumeration expected of type: '${enum.getClass}', but it does not appear to contain the value: '$value'")
        }

      }
      case _ => JsError(s"Invalid JSON: $json. Error in '${enum.getClass}' field. Possible values: ${enum.values}")
    }
  }

  class EnumWithIdsFormatter[T <: Enumeration](enum: T) extends Format[T#Value] {
    private val nameField = "name"
    private val idField   = "id"

    override def writes(o: T#Value): JsValue = JsObject(Map(idField -> JsNumber(o.id), nameField -> JsString(o.toString)))

    override def reads(json: JsValue): JsResult[T#Value] = json match {
      case JsObject(values) =>
        values.get(idField) match {
          case Some(JsNumber(value)) if value <= enum.maxId && value >= 0 ⇒
            try {
              JsSuccess(enum(value.toInt))
            } catch {
              case _: NoSuchElementException =>
                JsError(
                  s"Enumeration expected of type: '${enum.getClass}', but it does not appear to contain the value: '$value'")
            }

          case Some(JsNumber(x)) ⇒
            JsError(s"Invalid JSON:$json. Field '$idField': '$x' is out of range. Possible values:${enum.values.map(_.id)}")

          case Some(_) ⇒
            JsError(s"Invalid JSON:$json. Field '$idField' isn't number. Possible values:${enum.values.map(_.id)}")

          case None ⇒
            JsError(s"Invalid JSON:$json. Missing field '$idField'")
        }

      case _ =>
        JsError(s"Invalid JSON: $json")
    }

  }

}

现在我要验证json

import play.api.libs.json.Json
import play.api.libs.functional.syntax._

    val obj = SearchRequestMessage(UUID.randomUUID(), UUID.randomUUID(), "email", SearchByTypes.Emails)

    val json = Json.toJson(obj)


    val result = ((json \ "jobId").validate[UUID] and
      (json \ "offerId").validate[UUID] and
      (json \ "search").validate[String] and
      (json \ "searchByType").validate[SearchByType])(SearchRequestMessage[String].apply(_,_,_,_))

并出现错误:

Error:(41, 75) missing argument list for method apply in object SearchRequestMessage
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `apply _` or `apply(_,_,_,_)` instead of `apply`.
      (json \ "searchByType").validate[SearchByType])(SearchRequestMessage[String].apply(_,_,_,_))

如何解决此错误?

2 个答案:

答案 0 :(得分:0)

尝试

(json \ "searchByType").validate[SearchByType])(SearchRequestMessage[String].apply)

或(有点冗长)

(json \ "searchByType").validate[SearchByType])((a,b,c,d) => SearchRequestMessage[String].apply(a,b,c,d))

答案 1 :(得分:0)

这有效

((json \ "jobId").validate[UUID] and
    (json \ "offerId").validate[UUID] and
    (json \ "search").validate[String] and
    (json \ "searchByType").validate[SearchByType])((a: UUID, b: UUID, c: String, d: SearchByType) => SearchRequestMessage.apply[String](a,b,c,d))