Search code examples
scalaplayframework-2.2scala-2.10reactivemongo

Json Coast to Coast Play framework : Serializing Joda DateTime


Hi all I am new to play framework, if someone knows of a better approach then mentioned below please let me know.

So I have a model and Reads/Writes/Format for it

case class Schedule (startDate: DateTime, endDate: DateTime)


object ScheduleSerializers {


  val userDateFormatter = "dd/MM/yyyy HH:mm:ss"
  val nonImplicitUserFormatter = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss")
  implicit val jodaDateTimeReads = Reads.jodaDateReads(userDateFormatter)
  implicit val jodaDateTimeWrites = Writes.jodaDateWrites(userDateFormatter)

  implicit val readSchedule: Reads[Schedule] = (
    (__ \ "startDate").read[String].map[DateTime](dt => DateTime.parse(dt, nonImplicitUserFormatter)) and
      (__ \ "endDate").read[String].map[DateTime](dt => DateTime.parse(dt, nonImplicitUserFormatter))
    )(Schedule)

  implicit val writeSchedule: Writes[Schedule] = (
    (__ \ "startDate").write[String].contramap[DateTime](dt => nonImplicitUserFormatter.print(dt)) and
      (__ \ "endDate").write[String].contramap[DateTime](dt => nonImplicitUserFormatter.print(dt))
    )(unlift(Schedule.unapply))

  implicit val formatSchdule = Format(readSchedule, writeSchedule)

}

Now I open the play console and do this

val sch = Json.parse(""" {
     | 
     |   "schedule" : { "starDate" : "04/02/2011 20:27:05" , "endDate" : "04/02/2011 20:27:05" }
     | }
     | """)
sch: play.api.libs.json.JsValue = {"schedule":{"starDate":"04/02/2011 20:27:05","endDate":"04/02/2011 20:27:05"}}

sch.validate[Schedule]
res0: play.api.libs.json.JsResult[models.experiment.Schedule] = JsError(List((/endDate,List(ValidationError(error.path.missing,WrappedArray()))), (/startDate,List(ValidationError(error.path.missing,WrappedArray())))))

I am getting an Error, but if I try to parse a single date for ex:

scala> val singleDate = Json.parse(""" "04/02/2011 20:27:05" """)
singleDate: play.api.libs.json.JsValue = "04/02/2011 20:27:05"

singleDate.validate[DateTime]
res1: play.api.libs.json.JsResult[org.joda.time.DateTime] = JsSuccess(2011-02-04T20:27:05.000-08:00,)

I am confused as to why 'singleDate' works but the validation on the 'Schedule' model fails. Thanks in advance, any help will be appreciated.


Solution

  • The error is rather clear: "path missing".

    Instead of:

     (__ \ "startDate") ...
     (__ \ "endDate") ...
    

    You have to give the real path:

     (__ \ "schedule" \ "startDate") ...
     (__ \ "schedule" \ "endDate") ...
    

    By the way, as you define jodaDateTimeReads as implicit, you don't need to do the pasing by hand. And as you reads and writes are doing the same, just go with Format.

    That should be enough:

    implicit val formatSchedule: Format[Schedule] = (
      (__ \ "startDate").read[DateTime] and
      (__ \ "endDate").read[DateTime]
    )(Schedule.apply, unlift(Schedule.unapply)))