我试图使用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)
}
}
}
答案 0 :(得分:14)
这不是使用validate
的正确方法。我并不认为文档会尽可能地强调它的重要性,但在Using Validation
一节中已经解释了here。
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.
}
)
让我们稍微研究一下。 fold
上JsResult
的签名如下:
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)
然后在buildConfig
:
EventConfig.apply
代替Reads
implicit val jsonReads: Reads[EventConfig] = (
(__ \ "time").read[Long] and
(__ \ "param").read[Int]
)(buildConfig _)
我缩短了这个示例,但buildConfig
可以是任何返回EventConfig
的函数,参数与您尝试验证的JSON对象的参数匹配。
答案 1 :(得分:0)
验证取决于您的Reads方法,我在那里遇到了问题。我应该在阅读中抓住这个例外。