muster
muster copied to clipboard
Json4sCodec deserializer expects an object to deserialize joda DateTime from
Standalone DateTime value is serialized to string using a custom producer and deserialized back using a custom consumer just fine. However, when DateTime value is part of a case class, it is serialized to string, but fails to deserialize (causing the whole case class deserialization to fail) with a message:
MappingException: : Expected an object field for timestamp but found a JString (json4s_input.scala:44)
where timestamp is the name of the DateTime field.
do your formats include the joda time formats? This error suggests they don't
what's the source of DateTime? Is that the joda time one?
Can you share a snippet to reproduce this behavior?
I'm sorry, notification for the first message wound up in spam. Yes, it is org.joda.time.DateTime. Here is the code ("StackEvt" should "serialize to string and deserialize back" fails):
import muster.ast.{AstNode, TextNode}
import muster.input.Consumer
import muster.output.{Producer, OutputFormatter}
import org.joda.time.{DateTimeZone, DateTime}
import com.typesafe.scalalogging.LazyLogging
import org.specs2.mutable._
import org.json4s._
import muster.codec.json4s._
class LowLevelTest extends Specification with LazyLogging {
case class StackEvt (timestamp: DateTime)
implicit object DateTimeConsumer extends Consumer[DateTime] {
def consume(node: AstNode[_]): DateTime = node match {
case TextNode(value) =>
val timeZone = DateTimeZone.getDefault
DateTime.parse(value).withZone(timeZone) //otherwise the parsed DateTime won't equal the original
case n => throw new MappingException("Can't parse timestamp from ${n.getClass}")
}
}
implicit object DateTimeProducer extends Producer[DateTime] {
def produce(value: DateTime, formatter: OutputFormatter[_]) = formatter.string(value.toString)
}
"Joda DateTime" should {
"serialize to string and deserialize back" in {
val now = new DateTime
val nowSerialized = Json4sCodec.from(now)
val back = Json4sCodec.as[DateTime](nowSerialized)
/* Note: even if string representations of DateTime objects are the same, the objects may not be
equal by hashcode. See
http://stackoverflow.com/questions/21002385/datetime-does-not-equal-itself-after-unserialization
*/
logger.debug("Joda DateTime now and back: " + now.toString + " " + back.toString)
back shouldEqual now
}
}
"StackEvt" should {
"serialize to string and deserialize back" in {
val testEvent = StackEvt (timestamp = new DateTime)
val json = Json4sCodec.from(testEvent)
val back = Json4sCodec.as[StackEvt](json)
back shouldEqual testEvent
}
}
}
Similar thing happens with Java Date, only in this case the deserializer expects a JString and fails when it gets anything else.
What are the fully qualified class names of formats you are referring to?
that was me being confused. I thought this was in the json4s repo not muster
I have put together a project to illustrate the issue.