Как десериализовать DateTime в Lift
У меня возникли проблемы с десериализацией поля org.joda.time.DateTime из JSON в класс case.
JSON:val ajson=parse(""" { "creationDate": "2013-01-02T10:48:41.000-05:00" }""")
Я также установил эти параметры сериализации:implicit val formats = Serialization.formats(NoTypeHints) ++ net.liftweb.json.ext.JodaTimeSerializers.all
И десериализация:val val1=ajson.extract[Post]
где сообщение:case class Post(
Дата создания: DateTime){ ... }
Исключение, которое я получаю:
net.liftweb.json.MappingException: No usable value for creationDate
Invalid date format 2013-01-02T10:48:41.000-05:00
Как я могу десериализовать эту строку даты в объект DateTime?
РЕДАКТИРОВАТЬ:
Это работает: val date3= new DateTime("2013-01-05T06:24:53.000-05:00")
который использует ту же строку даты из JSON, что и при десериализации. Что тут происходит?
2 ответа
Похоже, это DateParser
формат, который Lift использует по умолчанию. Копаясь в коде, вы можете увидеть, что парсер пытается использовать DateParser.parse(s, format)
перед передачей результата в конструктор для org.joda.time.DateTime
,
object DateParser {
def parse(s: String, format: Formats) =
format.dateFormat.parse(s).map(_.getTime).getOrElse(throw new MappingException("Invalid date format " + s))
}
case object DateTimeSerializer extends CustomSerializer[DateTime](format => (
{
case JString(s) => new DateTime(DateParser.parse(s, format))
case JNull => null
},
{
case d: DateTime => JString(format.dateFormat.format(d.toDate))
}
))
Формат, который, кажется, использует Lift: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
Чтобы обойти это, вы можете либо указать правильный шаблон и добавить его в параметры сериализации, либо, если вы предпочитаете, чтобы конструктор JodaTime выполнял всю работу, вы можете создать свой собственный сериализатор, например:
case object MyDateTimeSerializer extends CustomSerializer[DateTime](format => (
{
case JString(s) => tryo(new DateTime(s)).openOr(throw new MappingException("Invalid date format " + s))
case JNull => null
},
{
case d: DateTime => JString(format.dateFormat.format(d.toDate))
}
))
А затем добавить это в свой список форматов, а не net.liftweb.json.ext.JodaTimeSerializers.all
Не возможно на 100% элегантно, но это всего лишь несколько строк, вполне читабельно и работает:
val SourISODateTimeFormat = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss.SSSZ")
val IntermediateDateTimeFormat = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss'Z'")
def transformTimestamps(jvalue: JValue) = jvalue.transform {
case JField(name @ ("createdTime" | "updatedTime"), JString(value)) =>
val dt = SourceISODateTimeFormat.parseOption(value).get
JField(name, JString(IntermediateDateTimeFormat.print(dt)))
}