Json Coast to Coast Play framework : Serializing J

2019-05-22 14:08发布

问题:

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.

回答1:

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)))


回答2:

Try these:

implicit val dateWrites = jodaDateWrites("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
implicit val dateReads = jodaDateReads("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

https://github.com/playframework/playframework/blob/master/framework/src/play-json/src/main/scala/play/api/libs/json/Writes.scala#L411

https://github.com/playframework/playframework/blob/master/framework/src/play-json/src/main/scala/play/api/libs/json/Reads.scala#L645