json4s "Can't convert JString(2019-04-28T01:23:45.678Z) to class java.time.Instant"?
json4s "Can't convert JString(2019-04-28T01:23:45.678Z) to class java.time.Instant"?
在我的案例 class 中,我正在努力让 json4s 使用 java.time.Instant 值。 REPL 看起来像这样。
scala> case class TestTime(tag: String, t: java.time.Instant)
defined class TestTime
scala> import org.json4s._
import org.json4s._
scala> import org.json4s.ext.JavaTimeSerializers
import org.json4s.ext.JavaTimeSerializers
scala> import org.json4s.native.JsonMethods._
import org.json4s.native.JsonMethods._
scala> implicit lazy val formats = DefaultFormats ++ JavaTimeSerializers.all
formats: org.json4s.Formats = <lazy>
scala> val parsed = parse("""{"tag": "second","t": "2019-04-28T01:23:45.678Z"}""")
parsed: org.json4s.JValue = JObject(List((tag,JString(second)), (t,JString(2019-04-28T01:23:45.678Z))))
scala> val second = parsed.extract[TestTime]
org.json4s.package$MappingException: No usable value for t
Can't convert JString(2019-04-28T01:23:45.678Z) to class java.time.Instant
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:569)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.applyOrElse(Extraction.scala:593)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.applyOrElse(Extraction.scala:591)
at scala.PartialFunction.$anonfun$runWith$adapted(PartialFunction.scala:145)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:62)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:55)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:49)
at scala.collection.TraversableLike.collect(TraversableLike.scala:274)
at scala.collection.TraversableLike.collect$(TraversableLike.scala:272)
at scala.collection.AbstractTraversable.collect(Traversable.scala:108)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:591)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:651)
at org.json4s.Extraction$.$anonfun$extract(Extraction.scala:410)
at org.json4s.Extraction$.$anonfun$customOrElse(Extraction.scala:658)
at scala.PartialFunction.applyOrElse(PartialFunction.scala:127)
at scala.PartialFunction.applyOrElse$(PartialFunction.scala:126)
at scala.PartialFunction$$anon.applyOrElse(PartialFunction.scala:257)
at org.json4s.Extraction$.customOrElse(Extraction.scala:658)
at org.json4s.Extraction$.extract(Extraction.scala:402)
at org.json4s.Extraction$.extract(Extraction.scala:40)
at org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21)
... 36 elided
Caused by: org.json4s.package$MappingException: Can't convert JString(2019-04-28T01:23:45.678Z) to class java.time.Instant
at org.json4s.CustomSerializer$$anonfun$deserialize.applyOrElse(Formats.scala:450)
at org.json4s.CustomSerializer$$anonfun$deserialize.applyOrElse(Formats.scala:447)
at org.json4s.Extraction$.customOrElse(Extraction.scala:658)
at org.json4s.Extraction$.extract(Extraction.scala:402)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:554)
... 56 more
scala> val instant = java.time.Instant.parse("2014-12-03T10:15:30.00Z")
instant: java.time.Instant = 2014-12-03T10:15:30Z
我如何摆脱那个堆栈跟踪并让这个提取工作?
查看源代码,Instant
的自定义序列化程序将仅解析 Int
值,而不解析 String
值:
case object JInstantSerializer extends CustomSerializer[Instant]( format => (
{
case JInt(d) => Instant.ofEpochMilli(d.toLong)
case JNull => null
},
{
case d: Instant => JInt(d.toEpochMilli)
}
))
您可以添加一个规则来解析 String
到 Instant
以解决问题。
case object MyInstantSerialzer extends CustomSerializer[Instant]( format => (
{
case JInt(d) => Instant.ofEpochMilli(d.toLong)
case JString(s) => Instant.parse(s)
case JNull => null
},
{
case d: Instant => JInt(d.toEpochMilli)
}
))
implicit lazy val formats = DefaultFormats + MyInstantSerialzer
我个人认为这是错误的,因为当 read/writing 到 JSON
时,它不会保持 Instant
的准确性。这样感觉好多了:
case object MyInstantSerialzer extends CustomSerializer[Instant]( format => (
{
case JString(s) => Instant.parse(s)
case JNull => null
},
{
case s: Instant => JString(s.toString)
}
))
的答案中还有一个更复杂的解决方案
在我的案例 class 中,我正在努力让 json4s 使用 java.time.Instant 值。 REPL 看起来像这样。
scala> case class TestTime(tag: String, t: java.time.Instant)
defined class TestTime
scala> import org.json4s._
import org.json4s._
scala> import org.json4s.ext.JavaTimeSerializers
import org.json4s.ext.JavaTimeSerializers
scala> import org.json4s.native.JsonMethods._
import org.json4s.native.JsonMethods._
scala> implicit lazy val formats = DefaultFormats ++ JavaTimeSerializers.all
formats: org.json4s.Formats = <lazy>
scala> val parsed = parse("""{"tag": "second","t": "2019-04-28T01:23:45.678Z"}""")
parsed: org.json4s.JValue = JObject(List((tag,JString(second)), (t,JString(2019-04-28T01:23:45.678Z))))
scala> val second = parsed.extract[TestTime]
org.json4s.package$MappingException: No usable value for t
Can't convert JString(2019-04-28T01:23:45.678Z) to class java.time.Instant
at org.json4s.reflect.package$.fail(package.scala:95)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:569)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.applyOrElse(Extraction.scala:593)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun.applyOrElse(Extraction.scala:591)
at scala.PartialFunction.$anonfun$runWith$adapted(PartialFunction.scala:145)
at scala.collection.mutable.ResizableArray.foreach(ResizableArray.scala:62)
at scala.collection.mutable.ResizableArray.foreach$(ResizableArray.scala:55)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:49)
at scala.collection.TraversableLike.collect(TraversableLike.scala:274)
at scala.collection.TraversableLike.collect$(TraversableLike.scala:272)
at scala.collection.AbstractTraversable.collect(Traversable.scala:108)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:591)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:651)
at org.json4s.Extraction$.$anonfun$extract(Extraction.scala:410)
at org.json4s.Extraction$.$anonfun$customOrElse(Extraction.scala:658)
at scala.PartialFunction.applyOrElse(PartialFunction.scala:127)
at scala.PartialFunction.applyOrElse$(PartialFunction.scala:126)
at scala.PartialFunction$$anon.applyOrElse(PartialFunction.scala:257)
at org.json4s.Extraction$.customOrElse(Extraction.scala:658)
at org.json4s.Extraction$.extract(Extraction.scala:402)
at org.json4s.Extraction$.extract(Extraction.scala:40)
at org.json4s.ExtractableJsonAstNode.extract(ExtractableJsonAstNode.scala:21)
... 36 elided
Caused by: org.json4s.package$MappingException: Can't convert JString(2019-04-28T01:23:45.678Z) to class java.time.Instant
at org.json4s.CustomSerializer$$anonfun$deserialize.applyOrElse(Formats.scala:450)
at org.json4s.CustomSerializer$$anonfun$deserialize.applyOrElse(Formats.scala:447)
at org.json4s.Extraction$.customOrElse(Extraction.scala:658)
at org.json4s.Extraction$.extract(Extraction.scala:402)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:554)
... 56 more
scala> val instant = java.time.Instant.parse("2014-12-03T10:15:30.00Z")
instant: java.time.Instant = 2014-12-03T10:15:30Z
我如何摆脱那个堆栈跟踪并让这个提取工作?
查看源代码,Instant
的自定义序列化程序将仅解析 Int
值,而不解析 String
值:
case object JInstantSerializer extends CustomSerializer[Instant]( format => (
{
case JInt(d) => Instant.ofEpochMilli(d.toLong)
case JNull => null
},
{
case d: Instant => JInt(d.toEpochMilli)
}
))
您可以添加一个规则来解析 String
到 Instant
以解决问题。
case object MyInstantSerialzer extends CustomSerializer[Instant]( format => (
{
case JInt(d) => Instant.ofEpochMilli(d.toLong)
case JString(s) => Instant.parse(s)
case JNull => null
},
{
case d: Instant => JInt(d.toEpochMilli)
}
))
implicit lazy val formats = DefaultFormats + MyInstantSerialzer
我个人认为这是错误的,因为当 read/writing 到 JSON
时,它不会保持 Instant
的准确性。这样感觉好多了:
case object MyInstantSerialzer extends CustomSerializer[Instant]( format => (
{
case JString(s) => Instant.parse(s)
case JNull => null
},
{
case s: Instant => JString(s.toString)
}
))