JSON 到 case class 用 json4s 泛型解码
JSON to case class with generics decoding with json4s
我正在尝试使用 json4s 构建一个 json 到案例 class en/decoder
使用泛型 icw Manifest 似乎适用于普通 types/classes,但更复杂的配置似乎会失败。
如何结合使用 json4s 从 json 字符串中提取更复杂的类型?
import org.json4s._
import org.json4s.native.JsonMethods._
implicit val formats = org.json4s.DefaultFormats
case class User(name:String)
case class Product(id:String)
case class Meta(count:Int)
case class ResultList[T: Manifest](meta: Meta, result: List[T])
// Without generics
case class ResultListUser(meta: Meta, result: List[User])
case class ResultListProduct(meta: Meta, result: List[Product])
// general decode method
def decode[T: Manifest](jsonStr: String): T = {
parse(jsonStr).extract[T]
}
// data
val userJson = """{"meta":{"count":2},"result":[{"name":"Tom"},{"name":"Lucas"}]}"""
val productJson = """{"meta":{"count":2},"result":[{"id":"123"},{"id":"456"}]}"""
val resultListUser = decode[ResultListUser](userJson)
resultListUser: ResultListUser = ResultListUser(Meta(2),List(User(Tom), User(Lucas)))
val resultListProduct = decode[ResultListProduct](productJson)
resultListProduct: ResultListProduct = ResultListProduct(Meta(2),List(Product(123), Product(456)))
val resultListUser2 = decode[ResultList[User]](userJson)
org.json4s.package$MappingException: No usable value for evidence
No constructor for type Manifest[User], JNothing
...
val resultListProduct2 = decode[ResultList[Product]](productJson)
org.json4s.package$MappingException: No usable value for evidence No
constructor for type Manifest[Product], JNothing at
org.json4s.reflect.package$.fail(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:91)
at
org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:522)
at
org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:542)
at
org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:542)
at
scala.collection.TraversableLike$$anonfun$map.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:230)
at
scala.collection.TraversableLike$$anonfun$map.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:230)
at
scala.collection.mutable.ResizableArray$class.foreach(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:55)
at
scala.collection.mutable.ArrayBuffer.foreach(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:44)
at
scala.collection.TraversableLike$class.map(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:230)
at
scala.collection.AbstractTraversable.map(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:100)
at
org.json4s.Extraction$ClassInstanceBuilder.instantiate(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:542)
at
org.json4s.Extraction$ClassInstanceBuilder.result(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:593)
at
org.json4s.Extraction$$anonfun$extract.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:396)
at
org.json4s.Extraction$$anonfun$extract.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:388)
at
org.json4s.Extraction$.customOrElse(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:602)
at
org.json4s.Extraction$.extract(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:388)
at
worksheet.worksheet(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:35)
Caused by: org.json4s.package$MappingException: No constructor for
type Manifest[Product], JNothing at
org.json4s.reflect.package$.fail(package.scala:95) at
org.json4s.Extraction$ClassInstanceBuilder$$anonfun$org$json4s$Extraction$ClassInstanceBuilder$$constructor.apply(Extraction.scala:477)
at
org.json4s.Extraction$ClassInstanceBuilder$$anonfun$org$json4s$Extraction$ClassInstanceBuilder$$constructor.apply(Extraction.scala:477)
at scala.Option.getOrElse(Option.scala:121) at
org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$constructor(Extraction.scala:477)
at
org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:532)
at
org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597)
at
org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:400)
at
org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:392)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606) at
org.json4s.Extraction$.extract(Extraction.scala:392) at
org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:514)
at
org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(Extraction.scala:546)
at
org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(Extraction.scala:546)
at
scala.collection.TraversableLike$$anonfun$map.apply(TraversableLike.scala:234)
at
scala.collection.TraversableLike$$anonfun$map.apply(TraversableLike.scala:234)
at
scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48)
at
scala.collection.TraversableLike$class.map(TraversableLike.scala:234)
at scala.collection.AbstractTraversable.map(Traversable.scala:104)
at
org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:546)
at
org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597)
at
org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:400)
at
org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:392)
at org.json4s.Extraction$.customOrElse(Extraction.scala:606) at
org.json4s.Extraction$.extract(Extraction.scala:392) at
org.json4s.Extraction$.extract(Extraction.scala:39) at
org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21)
at A$A7$A$A7.decode(json4sgenerics.sc:24) at
A$A7$A$A7.resultListProduct2$lzycompute(json4sgenerics.sc:37) at
A$A7$A$A7.resultListProduct2(json4sgenerics.sc:37) at
A$A7$A$A7.get$$instance$$resultListProduct2(json4sgenerics.sc:36) at
A$A7$.main(json4sgenerics.sc:92) at A$A7.main(json4sgenerics.sc) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497) at
org.jetbrains.plugins.scala.worksheet.MyWorksheetRunner.main(MyWorksheetRunner.java:22)
问题是您确实希望 Manifest
传递给 decode
但您可能不希望它传递给
case class ResultList[T: Manifest](meta: Meta, result: List[T])
问题是这段代码实际上被编译成类似
的东西
case class ResultList[T](meta: Meta, result: List[T])(implicit evidence: Manifest[T])
而这个 implicit
参数 evidence
正是 json4s 无法弄清楚如何从你的 JSON 为你提供的(此时它不能使用隐式分辨率也是如此,因为它仅在编译时完成)。
因此,如果您将 ResultList
更改为
case class ResultList[T](meta: Meta, result: List[T])
我希望只要 T
绑定到 Json4s 可以提取的内容,您的代码就能正常工作。
我正在尝试使用 json4s 构建一个 json 到案例 class en/decoder 使用泛型 icw Manifest 似乎适用于普通 types/classes,但更复杂的配置似乎会失败。
如何结合使用 json4s 从 json 字符串中提取更复杂的类型?
import org.json4s._
import org.json4s.native.JsonMethods._
implicit val formats = org.json4s.DefaultFormats
case class User(name:String)
case class Product(id:String)
case class Meta(count:Int)
case class ResultList[T: Manifest](meta: Meta, result: List[T])
// Without generics
case class ResultListUser(meta: Meta, result: List[User])
case class ResultListProduct(meta: Meta, result: List[Product])
// general decode method
def decode[T: Manifest](jsonStr: String): T = {
parse(jsonStr).extract[T]
}
// data
val userJson = """{"meta":{"count":2},"result":[{"name":"Tom"},{"name":"Lucas"}]}"""
val productJson = """{"meta":{"count":2},"result":[{"id":"123"},{"id":"456"}]}"""
val resultListUser = decode[ResultListUser](userJson)
resultListUser: ResultListUser = ResultListUser(Meta(2),List(User(Tom), User(Lucas)))
val resultListProduct = decode[ResultListProduct](productJson)
resultListProduct: ResultListProduct = ResultListProduct(Meta(2),List(Product(123), Product(456)))
val resultListUser2 = decode[ResultList[User]](userJson)
org.json4s.package$MappingException: No usable value for evidence
No constructor for type Manifest[User], JNothing
...
val resultListProduct2 = decode[ResultList[Product]](productJson)
org.json4s.package$MappingException: No usable value for evidence No constructor for type Manifest[Product], JNothing at org.json4s.reflect.package$.fail(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:91) at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:522) at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:542) at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:542) at scala.collection.TraversableLike$$anonfun$map.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:230) at scala.collection.TraversableLike$$anonfun$map.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:230) at scala.collection.mutable.ResizableArray$class.foreach(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:55) at scala.collection.mutable.ArrayBuffer.foreach(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:44) at scala.collection.TraversableLike$class.map(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:230) at scala.collection.AbstractTraversable.map(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:100) at org.json4s.Extraction$ClassInstanceBuilder.instantiate(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:542) at org.json4s.Extraction$ClassInstanceBuilder.result(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:593) at org.json4s.Extraction$$anonfun$extract.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:396) at org.json4s.Extraction$$anonfun$extract.apply(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:388) at org.json4s.Extraction$.customOrElse(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:602) at org.json4s.Extraction$.extract(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:388) at worksheet.worksheet(/Users/tomlous/Development/Scala/testjes/src/main/scala/json4sgenerics.sc:35)
Caused by: org.json4s.package$MappingException: No constructor for type Manifest[Product], JNothing at org.json4s.reflect.package$.fail(package.scala:95) at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$org$json4s$Extraction$ClassInstanceBuilder$$constructor.apply(Extraction.scala:477) at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$org$json4s$Extraction$ClassInstanceBuilder$$constructor.apply(Extraction.scala:477) at scala.Option.getOrElse(Option.scala:121) at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$constructor(Extraction.scala:477) at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:532) at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597) at org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:400) at org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:392) at org.json4s.Extraction$.customOrElse(Extraction.scala:606) at org.json4s.Extraction$.extract(Extraction.scala:392) at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:514) at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(Extraction.scala:546) at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.apply(Extraction.scala:546) at scala.collection.TraversableLike$$anonfun$map.apply(TraversableLike.scala:234) at scala.collection.TraversableLike$$anonfun$map.apply(TraversableLike.scala:234) at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:59) at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:48) at scala.collection.TraversableLike$class.map(TraversableLike.scala:234) at scala.collection.AbstractTraversable.map(Traversable.scala:104) at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:546) at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:597) at org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:400) at org.json4s.Extraction$$anonfun$extract.apply(Extraction.scala:392) at org.json4s.Extraction$.customOrElse(Extraction.scala:606) at org.json4s.Extraction$.extract(Extraction.scala:392) at org.json4s.Extraction$.extract(Extraction.scala:39) at org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21) at A$A7$A$A7.decode(json4sgenerics.sc:24) at A$A7$A$A7.resultListProduct2$lzycompute(json4sgenerics.sc:37) at A$A7$A$A7.resultListProduct2(json4sgenerics.sc:37) at A$A7$A$A7.get$$instance$$resultListProduct2(json4sgenerics.sc:36) at A$A7$.main(json4sgenerics.sc:92) at A$A7.main(json4sgenerics.sc) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.jetbrains.plugins.scala.worksheet.MyWorksheetRunner.main(MyWorksheetRunner.java:22)
问题是您确实希望 Manifest
传递给 decode
但您可能不希望它传递给
case class ResultList[T: Manifest](meta: Meta, result: List[T])
问题是这段代码实际上被编译成类似
的东西case class ResultList[T](meta: Meta, result: List[T])(implicit evidence: Manifest[T])
而这个 implicit
参数 evidence
正是 json4s 无法弄清楚如何从你的 JSON 为你提供的(此时它不能使用隐式分辨率也是如此,因为它仅在编译时完成)。
因此,如果您将 ResultList
更改为
case class ResultList[T](meta: Meta, result: List[T])
我希望只要 T
绑定到 Json4s 可以提取的内容,您的代码就能正常工作。