我要验证具有类型值的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(_,_,_,_))
如何解决此错误?
答案 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))