Gawrosz
Gawrosz

Reputation: 187

Play Framework, JSON Read combinator with overriden apply method

I am trying to make somethink like that:

case class Obj(name: String, list: List[Integer], isPossible: Boolean) {    
  override def apply(name: String, list: List[Integer]): Obj = {
    Obj(name, list, list.exists((x: Integer) => x >= 10 && x <= 100))
  }
}

implicit val objReads: Reads[Obj] = (
(__ \ "name").read[String] and
(__ \ "list").read[List[Integer]]
)(Book.apply _)

but it doesn't compile, it returns me a error:

Overloaded method value [apply] cannot be applied to  ((String, List[Integer], Boolean) => models.Api.Obj)

is it possible to do this, or just i have to have the same amount of fields in case class and in read combinator, and this is not possible

Upvotes: 2

Views: 742

Answers (1)

Michael Zajac
Michael Zajac

Reputation: 55569

There are a few problems here. First, the apply method for a case class is defined within it's companion object, not the case class itself. The second problem is that once you define the apply method within the companion object, it's going to cause an ambiguous reference error in Obj.apply _. This is because your declaration of apply is an overload, and not an override, since the signatures do not match.

One way to solve this would be to remove isPossible from the constructor of Obj, and instead make it a method or val. You would still be able to access it the same way.

case class Obj(name: String, list: List[Int]) {
    val isPossible: Boolean = list.exists((x: Int) => x >= 10 && x <= 100)
}

object Obj {
    implicit val objReads: Reads[Obj] = (
        (__ \ "name").read[String] and
        (__ \ "list").read[List[Int]]
    )(Obj.apply _)
}

The only problem this poses is that isPossible would no longer be included in JSON writes, which can be fixed like so:

implicit val objWrites: Writes[Obj] = (
    (__ \ "name").write[String] and
    (__ \ "list").write[List[Int]] and 
    (__ \ "isPossible").write[Boolean]
)( obj => (obj.name, obj.list, obj.isPossible) )

Alternatively, you could rename the overloaded apply to something else, and use that for Reads instead of Obj.apply. However, I think keeping isPossible as a val is better, because it's calculation would be done on object creation, and not when being passed to the constructor. This would ensure that you could not just call Obj("test", List(1), true) with an invalid state for isPossible.

Upvotes: 2

Related Questions