【问题标题】:Play 2.3 implicit json conversion causes null pointer exception播放2.3 隐式json转换导致空指针异常
【发布时间】:2014-12-22 19:54:50
【问题描述】:

我正在尝试将 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]

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

【问题讨论】:

    标签: json scala playframework playframework-2.3


    【解决方案1】:

    问题在于初始化顺序。 dealFormMapReads 依赖于隐含的 dealFormFilterMapReads,直到之后才定义。它会编译,因为找到了隐式,即使它没有被初始化,所以dealFormMapReads被读为null,最终导致NPE。

    延迟加载会修复它:

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

    或者您可以交换定义 Reads 的顺序。


    这里抛出的NPE和这个例子类似:

    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`
    

    【讨论】:

      【解决方案2】:

      问题是 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 所述),这在这种情况下更有意义。

      免责声明

      在 play 中使用 Json 宏启动需要 Scala 2.10 并且在 2.1.0 之后的 Play 版本上支持

      【讨论】:

        猜你喜欢
        • 2014-04-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-02
        • 2015-09-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多