score:1

One workaround would be to write an apply method that takes in the default value of count as an option and handles the construction (can't name it apply as we need an unambiguous name when building our Reads):

object Item{
  def applyOpt(id:Option[Int], name:String, description:Option[String], count:Option[Int]): Item = count.map{c =>
    Item(id, name, description, c)
  }.getOrElse{
    Item(id, name, description)
  }
}

Then you could use readNullable for the default value, which will pass an Option[Int] to applyOpt:

import play.api.libs.json._
import play.api.libs.functional.syntax._


implicit val itemReads: Reads[Item] = (
  (__ \ "id").readNullable[Int] and
  (__ \ "name").read[String] and
  (__ \ "description").readNullable[String] and
  (__ \ "count").readNullable[Int]
)(Item.applyOpt _)

Certainly not ideal, especially if you have several default fields, but a quick workaround that avoids having to deal with macros or reflection.

score:4

Almost. You can define a default value with an Option like this:

case class Item( description:Option[String] = Some("String"))

If you definitely do not want an option, you can have a look here:

Defaults for missing properties in play 2 JSON formats


Related Query

More Query from same tag