I'm trying to convert a type tag into a java class that maintains/persists normally-erased type parameters. There are quite a few libraries that benefit from conversions like these (such as Jackson, and Guice). I'm currently trying to migrate Manifest
based code to TypeTag
since Manifest
s are insufficient for some corner cases.
The JVM treats Arrays special in comparison to other data types. The difference between a classOf[Int]
and classOf[Array[Int]]
is that the method Class.isArray()
will return true for the latter.
The Manifest
implementation was simple. Manifest.erasure
was a Class
instance where isArray()
was already valid/true.
The TypeTag
implementation is trickier. There is no quick and easy erasure
method. In fact the 'similar' TypeTag variant, RuntimeMirror.runtimeClass
, prefers not to handle creating any Array based classes on our behalf. Read the documentation:
Note: If the Scala symbol is ArrayClass, a ClassNotFound exception is thrown because there is no unique Java class corresponding to a Scala generic array
To work around this I try to detect if it is an Array. If it is an array, then I manually create the class object. However, I've come across an additional edge case when Array has an unknown type argument.
First let me show you an example that is not a HigherKinded type.
import scala.reflect.runtime.universe._
class A[T]
val innerType = typeOf[A[Array[_]]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns true.
So far so good.
class B[T[_]]
val innerType = typeOf[B[Array]].asInstanceOf[TypeRefApi].args.head
innerType <:< typeOf[Array[_]] // Returns false.
I can't create a typeOf[Array] since it complains about the missing parameter. How can I detect that B has an type parameter of Array?
Also, what would the class instance look like in this case? Is it an Array[Object]?
Aucun commentaire:
Enregistrer un commentaire