Reputation: 140
I have a polymorphic method that takes a custom case class as a type parameter.
Now, in order to support several case classes (defined in a config file as a String), I need to convert a String to the tagType
of the case class.
For that, I used runtimeMirror
method to get the class from the String
,
and then I used manifestToTypeTag
to get the tagType
(Getting TypeTag from a classname string)
import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe
import scala.reflect.ManifestFactory
// My polymorphic method
def printMe[T](l: List[T])(implicit typeTag: TypeTag[T]): Unit = println(l)
// This works:
printMe(List("fdfg"))(typeTag[java.lang.String])
// Now, I want to build the typeTag dynamically from a String
val className = "java.lang.String" // a Custom case class
val mirror = universe.runtimeMirror(getClass.getClassLoader)
val cls = Class.forName(className)
// Getting the typeTag from the class name
val t = internal.manifestToTypeTag(mirror,ManifestFactory.classType(cls))
// Call of the method with the generated typeTag
printMe(List("fdfg"))(t)
// Compilation error
Error:(12, 31) type mismatch;
found : scala.reflect.api.Universe#TypeTag[Nothing]
required: reflect.runtime.universe.TypeTag[String]
Note: Nothing <: String, but trait TypeTag is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: String`. (SLS 3.2.10)
printMe(List("fdfg"))(t)
However, when I pass the typeTag
to my polymorphic method I get a "type match compilation error" shown above.
Indeed, my polymorphic method requires a TypeTag[MyClassToto]
, and the TypeTag
I generate is TypeTag[Nothing]
.
I wonder if is possible to cast the TypeTag
I have got, or may be I have to change the signature of my polymorphic method ?
Upvotes: 3
Views: 522
Reputation: 48420
Try suggestion from https://stackoverflow.com/a/23792152/5205022:
def printMe[T](l: List[T])(implicit typeTag: TypeTag[T]): Unit = println(l)
def stringToTypeTag[A](name: String): TypeTag[A] = {
val c = Class.forName(name)
val mirror = runtimeMirror(c.getClassLoader)
val sym = mirror.staticClass(name)
val tpe = sym.selfType
TypeTag(mirror, new api.TypeCreator {
def apply[U <: api.Universe with Singleton](m: api.Mirror[U]) =
if (m eq mirror) tpe.asInstanceOf[U # Type]
else throw new IllegalArgumentException(s"Type tag defined in $mirror cannot be migrated to other mirrors.")
})
}
printMe(List("fdfg"))(stringToTypeTag("java.lang.String"))
Upvotes: 3