[英]Play framework scala json validation exception
我正在嘗試使用play framework 2.2.2檢查我的Actor中的JsValue對象。 當我嘗試使用validate方法時,我收到異常而不是結果對象:
try {
val result = data.validate[EventConfig]
Logger.debug("Result: "+result")
} catch {
case e =>
Logger.error("Exception: "+e)
}
這是一個例外:
Exception: play.api.libs.json.JsResultException: JsResultException(errors:List((,List(ValidationError(error.expected.jsnumber,WrappedArray())))))
為什么會發生這種情況,我應該如何使用驗證方法?
======更新
我正在使用這樣的Reads實現:
implicit val EventConfig_reads = new Reads[EventConfig] {
def reads(json: JsValue): JsResult[EventConfig] = {
JsSuccess(new
EventConfig((json \ ConfigEventAttrs.PARAM).as[Int],
(json \ ConfigEventAttrs.PERIOD).as[Int],
(json \ ConfigEventAttrs.THRESHOLD).as[Int],
(json \ ConfigEventAttrs.TOGGLE).as[Boolean]))
}
}
解決方案是添加catch子句:
implicit val EventConfig_reads = new Reads[EventConfig] {
def reads(json: JsValue): JsResult[EventConfig] = {
try {
JsSuccess(new
EventConfig((json \ ConfigEventAttrs.PARAM).as[Int],
(json \ ConfigEventAttrs.PERIOD).as[Int],
(json \ ConfigEventAttrs.THRESHOLD).as[Int],
(json \ ConfigEventAttrs.TOGGLE).as[Boolean]))
} catch {
case e: JsResultException =>
JsError(e.errors)
}
}
}
這不是使用validate
的正確方法。 我不認為文檔會盡可能地強調它的重要性,但是在這里 ,在“ Using Validation
”一節中對此進行了解釋。
data.validate[EventConfig]
返回JsResult
而不是 EventConfig
。 處理錯誤的首選方法是fold
結果:
data.validate[EventConfig].fold(
error => {
// There were validation errors, handle them here.
},
config => {
// `EventConfig` has validated, and is now in the scope as `config`, proceed as usual.
}
)
我們來看一下。 如果在JsResult
上fold
的簽名如下:
fold[X](invalid: (Seq[(JsPath, Seq[ValidationError])]) ⇒ X, valid: (A) ⇒ X): X
它接受兩個函數作為參數,它們都返回相同類型的結果。 第一個函數是Seq[(JsPath, Seq[ValidationError])]) => X
在上面的代碼中, error
的類型為Seq[(JsPath, Seq[ValidationError])])
,它實際上只是一系列json路徑,它們的驗證錯誤已經存在。 在這里,您可以剖析這些錯誤並相應地返回相應的錯誤消息,或者在失敗時執行您可能需要的任何其他操作。
第二個函數映射A => X
,其中A
是JsResult
已經驗證的類型,在您的情況下是EventConfig
。 在這里,您將能夠直接處理EventConfig
類型。
引發和捕獲異常不是處理此問題的方法(很少是),因為您將丟失所有累積的驗證錯誤。
編輯:由於OP已經使用有關其定義的Reads
附加信息更新了他的問題。
定義的Reads
的問題在於它們as[T]
。 當調用as
,你試圖強制給定的json路徑輸入T
,否則會拋出異常。 因此,一旦達到第一個驗證錯誤,就會拋出異常,您將丟失所有后續錯誤。 你的用例相對簡單,所以我認為采用更現代的Reads
會更好。
import play.api.libs.json._
import play.api.libs.functional.syntax._
case class EventConfig(param: Int, period: Int, threshold: Int, toggle: Boolean)
object EventConfig {
implicit val jsonReads: Reads[EventConfig] = (
(__ \ ConfigEventAttrs.PARAM).read[Int] and
(__ \ ConfigEventAttrs.PERIOD).read[Int] and
(__ \ ConfigEventAttrs.THRESHOLD).read[Int] and
(__ \ ConfigEventAttrs.TOGGLE).read[Boolean]
)(EventConfig.apply _)
}
這要緊湊得多,並且使用函數語法會將所有驗證錯誤累積到JsResult
,而不是拋出異常。
編輯2:解決OP對不同apply
方法的需求。
如果您使用的構建JSON對象的參數與案例類的參數不同,請定義用於JSON Reads
而不是EventConfig.apply
的函數。 假設你的EventConfig
在JSON中真的是這樣的:
(time: Long, param: Int)
但相反,你希望它是這樣的:
case class EventConfig(time: Date, param: Int)
定義一個函數以從原始參數創建EventConfig
:
def buildConfig(time: Long, param: Int) = EventConfig(DateUtils.timeSecToDate(time), param)
然后在Reads
使用buildConfig
而不是EventConfig.apply
:
implicit val jsonReads: Reads[EventConfig] = (
(__ \ "time").read[Long] and
(__ \ "param").read[Int]
)(buildConfig _)
我縮短了這個例子,但buildConfig
可以是任何返回EventConfig
函數,參數與你試圖驗證的JSON對象的參數匹配。
驗證取決於您的Reads方法,我遇到了一個問題。 我應該在閱讀中抓住這個例外。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.