I'm new to Scala and exploring possibilities of implicit conversions and famous cake pattern. I tried to create the model class which has the id value listed as abstract type to avoid leaking implementation details. I also mixed it into cake pattern trait wrapper. Everything works fine except for implicit conversion from id to JSON (within Play framework). Scala compiler just can't find implicit conversion no matter what I do.
Here's the code that reproduces the the problem:
import anorm._
import play.api.libs.json._
trait Card {
type Key
val NoId: Key
val id: Key
val name: String
}
trait CardModelComponent {
val cardModel: CardModel
trait CardModel {
def findById(id: Long): Option[Card]
def findAll: Seq[Card]
def delete(id: Long)
def create(name: String): Option[Card]
}
}
trait CardModelComponentImpl extends CardModelComponent {
case class CardImpl(id: Pk[Long], name: String) extends Card {
type Key = Pk[Long]
object Key extends Writes[Key] {
implicit def writes(key: Key): JsValue = {
key match {
case Id(idVal: Long) => JsNumber(idVal)
case _ => JsNull
}
}
}
val NoId = NotAssigned
}
class CardModelImpl extends CardModel {
def findById(id: Long): Option[Card] = { None }
def findAll: Seq[Card] = { Seq(CardImpl(Id(1), "Some card"))}
def delete(id: Long) {}
def create(name: String): Option[Card] = { Some(CardImpl(Id(1), name)) }
}
}
object ComponentsRegistry extends
CardModelComponentImpl {
val cardModel = new CardModelImpl
}
val card = ComponentsRegistry.cardModel.create("Test card").get
Json.toJson(card.id)
Error output I'm getting is like follows:
> card: Card = CardImpl(1,Test card)
> <console>:19: error: No Json deserializer found for type card.Key. Try to implem
ent an implicit Writes or Format for this type.
Json.toJson(card.id)
^
Is there any way to make it work? Looks like cake pattern wrapping hides too much type information from compiler, as I guess from card.Key type name.
I also tried to create Writer implementation for Pk directly with same error as result.