简体   繁体   中英

validate json with type value

I wand to validate json that has a type value I have a case class SearchRequestMessage with a companion object with json writer Value T can be Long or 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)
        ))
  }
}

Also I have SearchByTypes enum

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)

}

enum formatter

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")
    }

  }

}

Now I want to validate 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(_,_,_,_))

and an error appear:

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(_,_,_,_))

How I can fix this error?

try

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

or (which is a bit verbose)

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

This works

((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))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM