播放2.3隐式json转换导致空指针异常

时间:2014-10-27 15:22:57

标签: json scala playframework playframework-2.3

我正在尝试将json解析为我的案例类DealFormMap

case class DealFormMap(limit: Option[Int], filter: Option[DealFormFilterMap])
case class DealFormFilterMap(date: Option[String], code: Option[String])

implicit val dealFormMapReads: Reads[DealFormMap] = (
    (JsPath \ "limit").readNullable[Int] and
    (JsPath \ "filter").readNullable[DealFormFilterMap]
)(DealFormMap)

implicit val dealFormFilterMapReads: Reads[DealFormFilterMap] = (
    (JsPath \ "date").readNullable[String] and
    (JsPath \ "code").readNullable[String]
)(DealFormFilterMap)

有问题的JSON和解析尝试

val str = """{"limit":10,"filter":{"date":"2014-10-27"}}"""
val frm = Json.parse(str).as[DealFormMap]

导致一个神秘的错误堆栈,我似乎无法破解

play.api.Application$$anon$1: Execution exception[[NullPointerException: null]]
    at play.api.Application$class.handleError(Application.scala:296) ~[play_2.11-2.3.5.jar:2.3.5]
    at play.api.DefaultApplication.handleError(Application.scala:402) [play_2.11-2.3.5.jar:2.3.5]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$14$$anonfun$apply$1.applyOrElse(PlayDefaultUpstreamHandler.scala:205) [play_2.11-2.3.5.jar:2.3.5]
    at play.core.server.netty.PlayDefaultUpstreamHandler$$anonfun$14$$anonfun$apply$1.applyOrElse(PlayDefaultUpstreamHandler.scala:202) [play_2.11-2.3.5.jar:2.3.5]
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36) [scala-library-2.11.2.jar:na]
Caused by: java.lang.NullPointerException: null
    at play.api.libs.json.PathReads$$anonfun$nullable$1$$anonfun$apply$7$$anonfun$apply$9.apply(JsConstraints.scala:65) ~[play-json_2.11-2.3.5.jar:2.3.5]
    at play.api.libs.json.PathReads$$anonfun$nullable$1$$anonfun$apply$7$$anonfun$apply$9.apply(JsConstraints.scala:63) ~[play-json_2.11-2.3.5.jar:2.3.5]
    at play.api.libs.json.JsResult$class.fold(JsResult.scala:76) ~[play-json_2.11-2.3.5.jar:2.3.5]
    at play.api.libs.json.JsSuccess.fold(JsResult.scala:9) ~[play-json_2.11-2.3.5.jar:2.3.5]
    at play.api.libs.json.PathReads$$anonfun$nullable$1$$anonfun$apply$7.apply(JsConstraints.scala:61) ~[play-json_2.11-2.3.5.jar:2.3.5]

我这里的想法已经不多了,可能是什么问题?

2 个答案:

答案 0 :(得分:27)

问题是初始化顺序。 dealFormMapReads取决于隐含的dealFormFilterMapReads,直到之后才定义。dealFormMapReads。它会编译,因为找到了隐式,即使它没有被初始化,所以null被读作implicit val dealFormMapReads: Reads[DealFormMap] = ( (JsPath \ "limit").readNullable[Int] and (JsPath \ "filter").lazyReadNullable[DealFormFilterMap](dealFormFilterMapReads) )(DealFormMap) ,最终导致NPE。

懒惰加载会修复它:

Reads

或者您可以只交换case class A(i: Int) object Test { val test = a.toString val a = A(1) } // Compiles up to here Test.test // throws NPE, because `a` was not initialized before `test` 定义的顺序。


此处抛出的NPE与此示例类似:

{{1}}

答案 1 :(得分:4)

问题是LimbSoup提到的顺序。但值得注意的是,使用Json macros可以使用

获得相同的结果
import play.api.libs.json._

implicit val dealFormFilterMapReads: Reads[DealFormFilterMap] = Json.reads[DealFormFilterMap]

implicit val dealFormMapReads: Reads[DealFormMap] = Json.reads[DealFormMap]

请注意,通过使用此宏,如果您更改了订单

implicit val dealFormMapReads: Reads[DealFormMap] = Json.reads[DealFormMap]

implicit val dealFormFilterMapReads: Reads[DealFormFilterMap] = Json.reads[DealFormFilterMap]   

您将收到以下有用的警告:

 Reference to uninitialized value dealFormFilterMapReads
[warn] implicit val dealFormMapReads: Reads[DealFormMap] = Json.reads[DealFormMap]
[warn]                                                                 ^
[warn] one warning found

你可以通过使dealFormFilterMapReads懒惰或重新排序来修复(再次由LimpSoup提到),在这种情况下更有意义。

声明

在游戏中使用Json宏启动需要Scala 2.10并且在2.1.0

之后的Play版本上受支持