0

I'm writing a web service using Scala Play. The functionality is ok but I'm refactoring some parts to make my code more readable and clean.

I've used implicit for each of my entity classes to make them convertable to Json. I've also injected toJson function to Seq[MyEntityClass] to be able to make an Json array by calling a single function.

It looks like this:

case class MyModel(id: Option[Int], foo: String, bar: String)

object MyModel {
  implicit val writer = Json.writes[MyModel]
  implicit val reader: Reads[MyModel] = new Reads[MyModel] {
    def reads(json: JsValue): JsResult[MyModel] = {
      for {
        foo <- (json \ "foo").validate[String]
        bar <- (json \ "bar").validate[String]
      } yield MyModel(None, foo, bar)
    }
  }

  implicit def richMyModelSeq(apps: Seq[MyModel]) = new {
    def toJson:JsValue = Json.toJson(apps)
  }
  // ...
}

How can I define this code in a super class to not repeat this code for each entity class?

Why this is not working?

abstract class Jsonable {
  implicit val writer = Json.writes[Jsonable]

  implicit def richMyModelSeq(apps: Seq[MyModel]) = new {
    def toJson:JsValue = Json.toJson(apps)
  }
}
case class MyModel(id: Option[Int], foo: String, bar: String)

object MyModel extends Jsonable{
  implicit val reader: Reads[MyModel] = new Reads[MyModel] {
    def reads(json: JsValue): JsResult[MyModel] = {
      for {
        foo <- (json \ "foo").validate[String]
        bar <- (json \ "bar").validate[String]
      } yield MyModel(None, foo, bar)
    }
  }
  // ...
}
Bardia Heydari
  • 777
  • 9
  • 24

1 Answers1

0

You could use something on the lines of: The classes can extend the trait and the companion objects can extend the MyModelComp.

import play.api.libs.json._

trait MyModel {
  def id: Option[Int]
  def foo: String
  def bar: String
}

trait MyModelComp[M <: MyModel] {

  def cons: MyModel => M

  implicit val writer = Json.writes[MyModel]
  implicit def reader[M]: Reads[M] = new Reads[M] {
    def reads(json: JsValue): JsResult[M] = {
      for {
        foo <- (json \ "foo").validate[String]
        bar <- (json \ "bar").validate[String]
      } yield cons(new MyModel {
        override def foo: String = ???

        override def bar: String = ???

        override def id: Option[Int] = ???
      })
    }
  }
}
Ashesh
  • 2,978
  • 4
  • 27
  • 47