The intention is to get at run-time some info of particular classes that is available only at compile-time.
My approach was to generate the info at compile time with a macro that expands to a map that contains the info indexed by the runtime class name. Something like this:
object macros {
def subClassesOf[T]: Map[String, Info] = macro subClassesOfImpl[T];
def subClassesOfImpl[T: ctx.WeakTypeTag](ctx: blackbox.Context): ctx.Expr[Map[String, Info]] = {
import ctx.universe._
val classSymbol = ctx.weakTypeTag[T].tpe.typeSymbol.asClass
val addEntry_codeLines: List[Tree] =
for {baseClassSymbol <- classSymbol.knownDirectSubclasses.toList} yield {
val key = baseClassSymbol.asType.toType.erasure.typeSymbol.fullName
q"""builder.addOne($key -> new Info("some info"));"""
}
q"""
val builder = Map.newBuilder[String, Info];
{..$addEntry_codeLines}
builder.result();""";
ctx.Expr[Map[String, Info]](body_code);
}
}
Which would we used like this:
object shapes {
trait Shape;
case class Box(h: Int, w: Int);
case class Sphere(r: Int);
}
val infoMap = subclassesOf[shapes.Shape];
val box = Box(3, 7);
val infoOfBox = infoMap.get(box.getClass.getName)
The problem is that the names of the erased classes given by that macro are slightly different from the ones obtained at runtime by the someInstance.getClass.getName
method. The first uses dots to separate container from members, and the second uses dollars.
scala> infoMap.mkString("\n")
val res7: String =
shapes.Box -> Info(some info)
shapes.Sphere -> Info(some info)
scala> box.getClass.getName
val res8: String = shapes$Box
How is the correct way to obtain at compile time the name that a class will have at runtime?
Vice versa, at runtime, having Java name of a class (with dollars) you can obtain Scala name (with dots).
This can be done even with
replace
Anyway, at compile time you can try
One more option is to use runtime reflection inside a macro. Replace
with
where
This works only with classes existing at compile time. So the project should be organized as follows
Shape
,Box
,Sphere
def subClassesOf...
subclassesOf[shapes.Shape]...