簡體   English   中英

播放框架scala json驗證異常

[英]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.
   }
)

我們來看一下。 如果在JsResultfold的簽名如下:

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 ,其中AJsResult已經驗證的類型,在您的情況下是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM