0

The Play 2.5.x docs do not provide an example I can use to try and sort my problem with defining an implicit Reads[T] for my model.

Could someone point out what I am doing wrong please?

My model:

case class Entry(id: Int, typ: String, caught: ZonedDateTime)
case class Data(entries: Seq[Entry])

The following Reads for the Entry type is fine.

 implicit val entryReads: Reads[Entry] = (
      (__ \ "id").read[Int] and
      (__ \ "typ").read[String] and
      (__ \ "caught").read[ZonedDateTime]
    )(Entry.apply _)

The problem

is with my Reads[Data] below. The compiler is complaining that it needs a Data instead of an Entry.

Found: Reads[api.test.Entry] required: Reads[api.test.Data]

implicit val dataReads: Reads[Data] = (JsPath \ "entries").read[Seq[Entry]]

If I modify Data so that it has multiple fields.

case class Data(entries: Seq[Entry], someStr: String)

Then my dataReads using the combinator compiles fine.

 implicit val dataReads: Reads[Data] = (
      (__ \ "entries").read[Seq[Entry]] and
      (__ \ "someStr").read[String]
    )(Data.apply _)

The problem is my Data does not really need that String.

The Play docs contain plenty of examples of defining implicit Reads/Writes for Case classes with more than a single field but none that have a single field.

2 Answers2

1

Have a look at map.

implicit val dataReads: Reads[Data] = (
        (__ \ "entries").read[Seq[Entry]].map(Data(_))
    )

You might be interested in this post if you need to define a Writes[T] as well - How to write a Play JSON writes converter for a case class with a single nullable member

Community
  • 1
  • 1
jacks
  • 4,614
  • 24
  • 34
0

If you use multiply fields, you use functional syntax and FunctionalBuilder.apply function, which fills Data.apply parameters:

implicit val dataReads: Reads[Data] = (... and ...)(Data.apply _)

is same

val dataBuilder: FunctionalBuilder[Reads]#CanBuild2[Seq[Entry], String] = (... and ...)

implicit val dataReads: Reads[Data] = dataBuilder(Data.apply _)

For one field Reads functional syntax is not used, so you must fill Data.apply parameters by yourself with mapping (__ \ "entries") to Data.entries

implicit val dataReads: Reads[Data] = (
  (__ \ "entries").read[Seq[Entry]].map(Data)
)
andrey.ladniy
  • 1,664
  • 1
  • 11
  • 27