Hi,
I am struggling with a macro that demux’s an object’s type and calls corresponding json serializer. I have tried two ways of writing the match/case for demux’ing. Any help is much appreciated!
Method 1
val tpe = c.parse(animalClassName)
val caseStmt = cq"""a: $tpe => Json.toJson(a)($writer)"""
If I use this to generate the cases, I get the following error:
cala> AnimalMacros.toJson(myCat.asInstanceOf[Animal])
case (a @ ((): Cat)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((): Dog)) => Json.toJson(a)(Dog.jsonWrites)
{
import play.api.libs.json.;
$line32.$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.myCat.asInstanceOf[$line31.$read.$iw.$iw.$iw.$iw.$iw.$iw.Animal] match {
case (a @ ((): Cat)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((_): Dog)) => Json.toJson(a)(Dog.jsonWrites)
}
}
:1: error: not found: value Cat
Cat
^
Method 2
If I use the class name string directly as follows:
val caseStmt = cq""“a: $animalClassName => Json.toJson(a)($writer)”""
I get this error:
scala> AnimalMacros.toJson(myCat.asInstanceOf[Animal])
case (a @ ((): “Cat”)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((): “Dog”)) => Json.toJson(a)(Dog.jsonWrites)
{
import play.api.libs.json.;
$line32.$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.myCat.asInstanceOf[$line31.$read.$iw.$iw.$iw.$iw.$iw.$iw.Animal] match {
case (a @ ((): “Cat”)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((_): “Dog”)) => Json.toJson(a)(Dog.jsonWrites)
}
}
:26: warning: fruitless type test: a value of type Animal cannot also be a String (the underlying of String(“Cat”))
AnimalMacros.toJson(myCat.asInstanceOf[Animal])
^
:26: error: pattern type is incompatible with expected type;
found : String(“Cat”)
required: Animal
AnimalMacros.toJson(myCat.asInstanceOf[Animal])
^
----- complete code ------
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.language.experimental.macros
import play.api.libs.json._
trait Animal
case class Cat(name: String)
object Cat {
val jsonFormats = Json.format[Cat]
val jsonWrites = new Writes[Cat] {
def writes(in: Cat) = Json.obj(
“animalType” -> classOf[Cat].getName,
“animalInstance” -> Json.toJson(in)(jsonFormats)
)
}
}
case class Dog(name: String)
object Dog {
val jsonFormats = Json.format[Dog]
val jsonWrites = new Writes[Dog] {
def writes(in: Dog) = Json.obj(
“animalType” -> classOf[Dog].getName,
“animalInstance” -> Json.toJson(in)(jsonFormats)
)
}
}
val animals = List(“Cat”, “Dog”)
object AnimalMacros {
import scala.reflect.macros.blackbox
def toJson(animalTree: Animal): JsValue = macro toJsonImpl
def toJsonImpl(c: blackbox.Context)(animalTree: c.Tree): c.universe.Tree = {
import c.universe._
val q"$animal" = animalTree
val caseStmts = animals.map { animalClassName =>
val writer = c.parse(s"$animalClassName.jsonWrites")
val tpe = c.parse(animalClassName)
val caseStmt = cq"""a: $tpe => Json.toJson(a)($writer)"""
// val caseStmt = cq"""a: $animalClassName => Json.toJson(a)($writer)"""
println(showCode(caseStmt))
caseStmt
}
// println(showCode(caseStmt))
val matchCase =
q"""
import play.api.libs.json._
$animal match { case ..$caseStmts }
"""
println(showCode(matchCase))
matchCase
}
}
// Exiting paste mode, now interpreting.
import scala.language.experimental.macros
import play.api.libs.json._
defined trait Animal
defined class Cat
defined object Cat
defined class Dog
defined object Dog
animals: List[String] = List(Cat, Dog)
defined object AnimalMacros
scala> val myCat = Cat(“feline”)
myCat: Cat = Cat(feline)
scala> AnimalMacros.toJson
toJson toJsonImpl
scala> AnimalMacros.toJson(myCat)
:25: error: type mismatch;
found : Cat
required: Animal
AnimalMacros.toJson(myCat)
^
scala> AnimalMacros.toJson(myCat.asInstanceOf[Animal])
case (a @ ((): “Cat”)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((): “Dog”)) => Json.toJson(a)(Dog.jsonWrites)
{
import play.api.libs.json.;
$line32.$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.myCat.asInstanceOf[$line31.$read.$iw.$iw.$iw.$iw.$iw.$iw.Animal] match {
case (a @ ((): “Cat”)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((_): “Dog”)) => Json.toJson(a)(Dog.jsonWrites)
}
}
:26: warning: fruitless type test: a value of type Animal cannot also be a String (the underlying of String(“Cat”))
AnimalMacros.toJson(myCat.asInstanceOf[Animal])
^
:26: error: pattern type is incompatible with expected type;
found : String(“Cat”)
required: Animal
AnimalMacros.toJson(myCat.asInstanceOf[Animal])
^
scala>
scala> AnimalMacros.toJson(myCat.asInstanceOf[Animal])
case (a @ ((): Cat)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((): Dog)) => Json.toJson(a)(Dog.jsonWrites)
{
import play.api.libs.json.;
$line32.$read.$iw.$iw.$iw.$iw.$iw.$iw.$iw.$iw.myCat.asInstanceOf[$line31.$read.$iw.$iw.$iw.$iw.$iw.$iw.Animal] match {
case (a @ ((): Cat)) => Json.toJson(a)(Cat.jsonWrites)
case (a @ ((_): Dog)) => Json.toJson(a)(Dog.jsonWrites)
}
}
:1: error: not found: value Cat
Cat
^