Playframework JSON 解析 - 空指针异常 - 当存在数组时
Playframework JSON parsing - Null pointer exception - when array is present
我正在使用 playframework 进行 JSON 解析,我面临以下 NullPointerException:
我的数据模型如下:
case class SearchLikeThisResult(total: Int, max_score: Double, hits: Seq[Hits])
case class Hits( index: String, typ: String, id: String, score: Double)
我的读者如下:
object SearchLikeThisHits {
import play.api.libs.functional.syntax._
implicit val searchLikeThisResult: Reads[SearchLikeThisResult] = (
(JsPath \ "total").read[Int] and
(JsPath \ "max_score").read[Double] and
(JsPath \ "hits").read[Seq[Hits]]
)(SearchLikeThisResult.apply _)
implicit val hitsReads: Reads[Hits] = (
(JsPath \ "_index").read[String] and
(JsPath \ "_type").read[String] and
(JsPath \ "_id").read[String] and
(JsPath \ "_score").read[Double]
)(Hits.apply _)
}
然后我有以下测试代码:
import play.api.libs.json.{JsValue, Json}
object Test extends App{
val str = """{"total": 53, "max_score": 3.2948244, "hits": [
{
"_index": "hovno",
"_type": "BYT",
"_id": "3413569628",
"_score": 3.2948244
},
{
"_index": "hovno22",
"_type": "BYT",
"_id": "3413569628",
"_score": 3.2948244
}
]
}"""
import SearchLikeThisHits.searchLikeThisResult
val json = Json.parse(str)
val r = json.as[SearchLikeThisResult]
}
这导致以下 NullPointerException:
Exception in thread "main" java.lang.NullPointerException
at play.api.libs.json.Json$.fromJson(Json.scala:115)
at play.api.libs.json.DefaultReads$$anon$$anonfun$reads.apply(Reads.scala:448)
at play.api.libs.json.DefaultReads$$anon$$anonfun$reads.apply(Reads.scala:447)
at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:111)
at scala.collection.immutable.List.foldLeft(List.scala:84)
at scala.collection.generic.TraversableForwarder$class.foldLeft(TraversableForwarder.scala:41)
at scala.collection.mutable.ListBuffer.foldLeft(ListBuffer.scala:45)
at play.api.libs.json.DefaultReads$$anon.reads(Reads.scala:447)
at play.api.libs.json.PathReads$$anonfun$at$$anonfun$apply.apply(JsConstraints.scala:36)
at play.api.libs.json.PathReads$$anonfun$at$$anonfun$apply.apply(JsConstraints.scala:36)
at play.api.libs.json.JsResult$class.flatMap(JsResult.scala:103)
at play.api.libs.json.JsSuccess.flatMap(JsResult.scala:9)
at play.api.libs.json.PathReads$$anonfun$at.apply(JsConstraints.scala:36)
at play.api.libs.json.PathReads$$anonfun$at.apply(JsConstraints.scala:36)
at play.api.libs.json.Reads$$anon.reads(Reads.scala:101)
at play.api.libs.json.Reads$$anon$$anon.reads(Reads.scala:81)
at play.api.libs.json.Reads$$anonfun$map.apply(Reads.scala:28)
at play.api.libs.json.Reads$$anonfun$map.apply(Reads.scala:28)
at play.api.libs.json.Reads$$anon.reads(Reads.scala:101)
at play.api.libs.json.JsValue$class.as(JsValue.scala:65)
at play.api.libs.json.JsObject.as(JsValue.scala:166)
at models.data.Test$delayedInit$body.apply(Test.scala:33)
at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main.apply(App.scala:71)
at scala.App$$anonfun$main.apply(App.scala:71)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
at scala.App$class.main(App.scala:71)
at models.data.Test$.main(Test.scala:9)
at models.data.Test.main(Test.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
如果我删除一个 json 数组,一切正常。我尝试了来自 playframework json 支持网页的类似示例,它可以正常工作。我在这里找不到问题。
我基于调试的猜测是隐式可能存在问题但不知道如何帮助自己。我尝试了“-Xprint:typer”编译器选项,但没有发现任何可疑之处。
如有任何提示,我们将不胜感激
这是一个初始化顺序问题。您需要在 Reads[SearchLikeThisResult]
之前定义Reads[Hits]
。它编译是因为符号存在于代码中,当 Reads[SearchLikeThisResult]
被初始化时, Reads[Hits]
不是。在它尝试解析 Hits
的数组并命中 NPE 之前,它不会被注意到。
所以只需调换顺序。这与 this answer.
有关
implicit val hitsReads: Reads[Hits] = (
(JsPath \ "_index").read[String] and
(JsPath \ "_type").read[String] and
(JsPath \ "_id").read[String] and
(JsPath \ "_score").read[Double]
)(Hits.apply _)
implicit val searchLikeThisResult: Reads[SearchLikeThisResult] = (
(JsPath \ "total").read[Int] and
(JsPath \ "max_score").read[Double] and
(JsPath \ "hits").read[Seq[Hits]]
)(SearchLikeThisResult.apply _)
我正在使用 playframework 进行 JSON 解析,我面临以下 NullPointerException:
我的数据模型如下:
case class SearchLikeThisResult(total: Int, max_score: Double, hits: Seq[Hits])
case class Hits( index: String, typ: String, id: String, score: Double)
我的读者如下:
object SearchLikeThisHits {
import play.api.libs.functional.syntax._
implicit val searchLikeThisResult: Reads[SearchLikeThisResult] = (
(JsPath \ "total").read[Int] and
(JsPath \ "max_score").read[Double] and
(JsPath \ "hits").read[Seq[Hits]]
)(SearchLikeThisResult.apply _)
implicit val hitsReads: Reads[Hits] = (
(JsPath \ "_index").read[String] and
(JsPath \ "_type").read[String] and
(JsPath \ "_id").read[String] and
(JsPath \ "_score").read[Double]
)(Hits.apply _)
}
然后我有以下测试代码:
import play.api.libs.json.{JsValue, Json}
object Test extends App{
val str = """{"total": 53, "max_score": 3.2948244, "hits": [
{
"_index": "hovno",
"_type": "BYT",
"_id": "3413569628",
"_score": 3.2948244
},
{
"_index": "hovno22",
"_type": "BYT",
"_id": "3413569628",
"_score": 3.2948244
}
]
}"""
import SearchLikeThisHits.searchLikeThisResult
val json = Json.parse(str)
val r = json.as[SearchLikeThisResult]
}
这导致以下 NullPointerException:
Exception in thread "main" java.lang.NullPointerException
at play.api.libs.json.Json$.fromJson(Json.scala:115)
at play.api.libs.json.DefaultReads$$anon$$anonfun$reads.apply(Reads.scala:448)
at play.api.libs.json.DefaultReads$$anon$$anonfun$reads.apply(Reads.scala:447)
at scala.collection.LinearSeqOptimized$class.foldLeft(LinearSeqOptimized.scala:111)
at scala.collection.immutable.List.foldLeft(List.scala:84)
at scala.collection.generic.TraversableForwarder$class.foldLeft(TraversableForwarder.scala:41)
at scala.collection.mutable.ListBuffer.foldLeft(ListBuffer.scala:45)
at play.api.libs.json.DefaultReads$$anon.reads(Reads.scala:447)
at play.api.libs.json.PathReads$$anonfun$at$$anonfun$apply.apply(JsConstraints.scala:36)
at play.api.libs.json.PathReads$$anonfun$at$$anonfun$apply.apply(JsConstraints.scala:36)
at play.api.libs.json.JsResult$class.flatMap(JsResult.scala:103)
at play.api.libs.json.JsSuccess.flatMap(JsResult.scala:9)
at play.api.libs.json.PathReads$$anonfun$at.apply(JsConstraints.scala:36)
at play.api.libs.json.PathReads$$anonfun$at.apply(JsConstraints.scala:36)
at play.api.libs.json.Reads$$anon.reads(Reads.scala:101)
at play.api.libs.json.Reads$$anon$$anon.reads(Reads.scala:81)
at play.api.libs.json.Reads$$anonfun$map.apply(Reads.scala:28)
at play.api.libs.json.Reads$$anonfun$map.apply(Reads.scala:28)
at play.api.libs.json.Reads$$anon.reads(Reads.scala:101)
at play.api.libs.json.JsValue$class.as(JsValue.scala:65)
at play.api.libs.json.JsObject.as(JsValue.scala:166)
at models.data.Test$delayedInit$body.apply(Test.scala:33)
at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
at scala.App$$anonfun$main.apply(App.scala:71)
at scala.App$$anonfun$main.apply(App.scala:71)
at scala.collection.immutable.List.foreach(List.scala:318)
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
at scala.App$class.main(App.scala:71)
at models.data.Test$.main(Test.scala:9)
at models.data.Test.main(Test.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
如果我删除一个 json 数组,一切正常。我尝试了来自 playframework json 支持网页的类似示例,它可以正常工作。我在这里找不到问题。 我基于调试的猜测是隐式可能存在问题但不知道如何帮助自己。我尝试了“-Xprint:typer”编译器选项,但没有发现任何可疑之处。
如有任何提示,我们将不胜感激
这是一个初始化顺序问题。您需要在 Reads[SearchLikeThisResult]
之前定义Reads[Hits]
。它编译是因为符号存在于代码中,当 Reads[SearchLikeThisResult]
被初始化时, Reads[Hits]
不是。在它尝试解析 Hits
的数组并命中 NPE 之前,它不会被注意到。
所以只需调换顺序。这与 this answer.
有关implicit val hitsReads: Reads[Hits] = (
(JsPath \ "_index").read[String] and
(JsPath \ "_type").read[String] and
(JsPath \ "_id").read[String] and
(JsPath \ "_score").read[Double]
)(Hits.apply _)
implicit val searchLikeThisResult: Reads[SearchLikeThisResult] = (
(JsPath \ "total").read[Int] and
(JsPath \ "max_score").read[Double] and
(JsPath \ "hits").read[Seq[Hits]]
)(SearchLikeThisResult.apply _)