joesan
joesan

Reputation: 15385

Play JSON Reads Error With Needed Implicits in Scope

I have a simple JSON reads and writes using the play json library:

  val dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  implicit val jodaDateTimeReads: Reads[DateTime] = Reads[DateTime](js =>
    js.validate[String].map[DateTime](dt =>
      DateTime.parse(dt, DateTimeFormat.forPattern(dateFormat))
    )
  )

  implicit val jodaDateTimeWrites: Writes[DateTime] = new Writes[DateTime] {
    def writes(dt: DateTime): JsValue = JsString(dt.toString())
  }

I'm trying to use this DateTime to parse one of my case class which is

case class DefaultMessage(timestamp: DateTime)

I have the corresponding reads and writes in scope and the reads and writes for the DateTime is also in scope:

implicit val defaultMessageReads: Reads[DefaultMessage] = (
  (JsPath \ "timestamp").read[DateTime](jodaDateTimeReads)
)(DefaultMessage.apply _)

I get an error that says:

[error]  found   : org.joda.time.DateTime => com.my.project.messages.DefaultMessage
[error]  required: play.api.libs.json.Reads[?]
[error]         )(DefaultMessage.apply _)

What does this imply? I thought the signature for the Reads[DefaultMessage] satisfies with the implicit val defaultMessageReads. I can't see what is wrong with this snippet?

Upvotes: 0

Views: 374

Answers (2)

Tomer
Tomer

Reputation: 2448

There you go.

case class DefaultMessage(timestamp: DateTime)
object DefaultMessage{
  val dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
  implicit val reads: Reads[DefaultMessage] =
    (json: JsValue) => (json \ "timestamp").validate[String]
      .map(t => DefaultMessage(DateTime.parse(t, DateTimeFormat.forPattern(dateFormat))))
}

You don't need to change your case class for that, although it makes more sense to have a message in a class called DefaultMessage:)

Upvotes: 1

joesan
joesan

Reputation: 15385

It seems to be a crazy issue! Seems like Play Json does not like case classes with a single parameter. I had to change my case class to:

case class DefaultMessage(message: String, timestamp: DateTime)

And then the reads and writes Format sort of works:

implicit val defaultMessageReads: Reads[DefaultMessage] = (
  (__ \ "message").read[String] and
  (__ \ "timestamp").read[DateTime](jodaDateTimeReads)
)(DefaultMessage.apply _)

implicit val defaultMessageWrites: Writes[DefaultMessage] = (
  (JsPath \ "message").write[String] and
  (JsPath \ "timestamp").write[DateTime](jodaDateTimeWrites)
)(unlift(DefaultMessage.unapply))

Upvotes: 0

Related Questions