如何序列化和反序列化Java 8 dateTime in lift JSON?

How to serialize and deserialize Java 8 dateTime in lift JSON?

我有一个案例class,我想先连载。然后在那之后,我想反序列化它以便在 MongoDB 中存储目的,但是 java 8 LocalDateTime 造成了问题。我从这个 link 中得到了帮助: how to deserialize DateTime in Lift 但没有运气。我无法为 java 8 日期时间编写它。 谁能帮我解决这个日期时间问题?这是我的代码:

import net.liftweb.json.Serialization.{read, write}

implicit val formats = Serialization.formats(NoTypeHints) 

case class Child(var str: String, var Num: Int, var abc: Option[String], MyList: List[Int], val dateTime: LocalDateTime = LocalDateTime.now())
val ser = write(Child("Mary", 5, None, List(1, 2)))
println("Child class converted to string" + ser) 

var obj = read[Child](ser)
println("object of Child is " + obj)

这是控制台上打印的错误消息:

(run-main-0) java.lang.ArrayIndexOutOfBoundsException: 49938
java.lang.ArrayIndexOutOfBoundsException: 49938
    at com.thoughtworks.paranamer.BytecodeReadingParanamer$ClassReader.<init>(BytecodeReadingParanamer.java:451)
    at com.thoughtworks.paranamer.BytecodeReadingParanamer$ClassReader.<init>(BytecodeReadingParanamer.java:431)
    at com.thoughtworks.paranamer.BytecodeReadingParanamer$ClassReader.<init>(BytecodeReadingParanamer.java:492)
    at com.thoughtworks.paranamer.BytecodeReadingParanamer$ClassReader.<init>(BytecodeReadingParanamer.java:337)
    at com.thoughtworks.paranamer.BytecodeReadingParanamer.lookupParameterNames(BytecodeReadingParanamer.java:100)
    at com.thoughtworks.paranamer.CachingParanamer.lookupParameterNames(CachingParanamer.java:75)
    at com.thoughtworks.paranamer.CachingParanamer.lookupParameterNames(CachingParanamer.java:68)
    at net.liftweb.json.Meta$ParanamerReader$.lookupParameterNames(Meta.scala:89)
    at net.liftweb.json.Meta$Reflection$.argsInfo(Meta.scala:237)
    at net.liftweb.json.Meta$Reflection$.constructorArgs(Meta.scala:253)
    at net.liftweb.json.Meta$Reflection$.net$liftweb$json$Meta$Reflection$$findMostComprehensive(Meta.scala:266)
    at net.liftweb.json.Meta$Reflection$$anonfun$primaryConstructorArgs.apply(Meta.scala:269)
    at net.liftweb.json.Meta$Reflection$$anonfun$primaryConstructorArgs.apply(Meta.scala:269)
    at net.liftweb.json.Meta$Memo.memoize(Meta.scala:199)
    at net.liftweb.json.Meta$Reflection$.primaryConstructorArgs(Meta.scala:269)
    at net.liftweb.json.Extraction$.decompose(Extraction.scala:88)
    at net.liftweb.json.Extraction$$anonfun.applyOrElse(Extraction.scala:91)
    at net.liftweb.json.Extraction$$anonfun.applyOrElse(Extraction.scala:89)
    at scala.collection.immutable.List.collect(List.scala:305)
    at net.liftweb.json.Extraction$.decompose(Extraction.scala:89)
    at net.liftweb.json.Serialization$.write(Serialization.scala:38)
    at TestActor$.delayedEndpoint$TestActor(TestActor.scala:437)
    at TestActor$delayedInit$body.apply(TestActor.scala:54)
    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:76)
    at scala.App$$anonfun$main.apply(App.scala:76)
    at scala.collection.immutable.List.foreach(List.scala:383)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35)
    at scala.App$class.main(App.scala:76)
    at TestActor$.main(TestActor.scala:54)
    at TestActor.main(TestActor.scala)
    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)

如果我从 case class 中删除 dateTime 参数,它工作正常。看来问题出在 dateTime.

我运行你的代码在我的 Intellij Idea 上,得到了同样的错误。试图调试原因,但调用堆栈太深,我最终放弃了。 但我猜可能是因为Lift没有为LocaleDateTime提供默认格式,就像你提到的post说的那样,"it is the DateParser format that Lift uses by default."

这里有一个折衷方案供大家参考,Lift-JSON为我们提供了默认的Date格式

// net.liftweb.json.Serialization Line 72
def formats(hints: TypeHints) = new Formats {
  val dateFormat = DefaultFormats.lossless.dateFormat
  override val typeHints = hints
}

因此,与其一路编写自定义的序列化程序,不如更改我们的数据类型以适应默认的日期格式。另外,net.liftweb.mongodb.DateSerializer(第 79 行)提供了对日期序列化的支持。

然后,我们可以提供方法来轻松获取LocaleDateTime。以下是我试图弄清楚的方法。

package jacoffee.scalabasic

import java.time.{ ZoneId, LocalDateTime }
import java.util.Date

// package object defined is for Scala compiler to look for implicit conversion for case class parameter date
package object Whosebug {
 implicit def toDate(ldt: LocalDateTime): Date =
   Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant())

 implicit def toLDT(date: Date): LocalDateTime =
   LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault())
}


package jacoffee.scalabasic.Whosebug

import java.time.LocalDateTime
import java.util.Date
import net.liftweb.json.{ NoTypeHints, Serialization }
import net.liftweb.json.Serialization.{ read, write }


case class Child(var str: String, var Num: Int, var abc: Option[String],
 myList: List[Int], val date : Date = LocalDateTime.now()) {
   def getLDT: LocalDateTime = date
 }

object DateTimeSerialization extends App {
   implicit val formats = Serialization.formats(NoTypeHints)

   val ser = write(Child("Mary", 5, None, List(1, 2)))
// Child class converted to string {"str":"Mary","Num":5,"myList":[1,2],"date":"2015-07-21T03:07:05.699Z"}
   println(" Child class converted to string " + ser)

   var obj=read[Child](ser)
   // Object of Child is Child(Mary,5,None,List(1, 2),Tue Jul 21 11:48:22 CST 2015)
   println(" Object of Child is "+ obj)
   // LocalDateTime of Child is 2015-07-21T11:48:22.075
   println(" LocalDateTime of Child is "+ obj.getLDT)
}

总之,希望对你有所帮助。