как да десериализирате 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(creationDate: 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 като при десериализацията. какво се случва тук


person Adrian    schedule 12.04.2013    source източник


Отговори (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

person jcern    schedule 14.04.2013
comment
Имам 2 допълнителни въпроса: (1) това ли е ГГГГ-ММ-дд'Т'ЧЧ:мм:сс.SSS'-'Z моят формат за дати като 2013-01-02T10:48:41.000-05:00 (2) това ли е правилният начин да добавя моя формат към формати: `implicit val formats = Serialization.formats(NoTypeHints) ++ MyDateTimeSerializer - person Adrian; 15.04.2013
comment
измислено (2): увийте MyDateTimeSerializer в списък: за интересуващите се изглежда така: implicit val formats = Serialization.formats(NoTypeHints) ++ List(MyDateTimeSerializer) - person Adrian; 15.04.2013
comment
Не съм много запознат с всички тънкости на шаблоните на DateFormat, но това, което предлагате, изглежда близко. Две неща, годината трябва да е с малки букви y и '-' е част от часовата зона (т.е. -5 часа от UTC), така че вероятно трябва да премахнете това. yyyy-MM-dd'T'HH:mm:ss.SSSZ Вероятно е близо до това, което търсите, но това може да има проблем с : в TZ. Що се отнася до добавянето на персонализирания сериализатор, опаковането му в List трябва да работи за вас. - person jcern; 15.04.2013
comment
добре, избрах (2) и не работи, но мисля, че синтактичният анализ е наред, но JSON низът може да има някои странни знаци в него, които трябва да бъдат екранирани. Направих извода, защото това работи new DateTime(parse(""" { "creationDate": "2013-01-05T06:24:53.000-05:00" }""").extract[Post3].creationDate), но когато JSON е даден като вход от потребителя, не работи val date3= new DateTime(parse(Text(name).toString()).extract[Post3].creationDate) - person Adrian; 15.04.2013

Може би не е 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)))
}
person Erik Kaplun    schedule 31.03.2014