Macro for serializing subclasses

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
^