How to obtain the raw datatype of a parameter of a field that is specialized in Scala via reflection?

梦想与她 提交于 2019-12-06 12:25:19

The Problem is you are using a Java reflection API which doesn't workaround the JVM's "Type Erasure" issue, because of that there's no way to find out the actual generic types with it.

Fortunately the coming 2.10 version of Scala implements new reflection API, which solves the type erasure issue. But since 2.10 hasn't been released yet, the API isn't standardized nor documented yet. Your best bet is to dig into it with some tool like debugger and ask more specific questions that come up here.

In Scala 2.10-M5 you can access the API like follows:

scala> reflect.runtime.universe.typeOf[(Int, String)]
res0: reflect.runtime.universe.Type = (Int, String)

scala> reflect.runtime.universe.typeOf[(Int, String)].typeArguments
res1: List[reflect.runtime.universe.Type] = List(Int, String)

scala> reflect.runtime.universe.typeOf[(Int, String)].typeArguments.head
res2: reflect.runtime.universe.Type = Int

Update #1

The following function shows how you can get a type of an instance:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> def typeOf[T : TypeTag](x : T) = reflect.runtime.universe.typeOf[T]
typeOf: [T](x: T)(implicit evidence$1: reflect.runtime.universe.TypeTag[T])reflect.runtime.universe.Type

scala> typeOf(Seq((1,"sldf"),(20,"sldkfjew")))
res0: reflect.runtime.universe.Type = Seq[(Int, String)]

In fact it's all based around the [T : TypeTag] part which tells the compiler to magically create an implicit instance of the reflection to the type passed.

Update #2

scala> class TupleReflection(val tuple: Tuple2[Int, String])
defined class TupleReflection

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> typeOf[TupleReflection].member(newTermName("tuple")).typeSignature
res6: reflect.runtime.universe.Type = => (scala.Int, String)

scala> typeOf[TupleReflection].members
res7: Iterable[reflect.runtime.universe.Symbol] = List(constructor TupleReflection, value tuple, value tuple, method $asInstanceOf, method $isInstanceOf, method synchronized, method ##, method !=, method ==, method ne, method eq, constructor Object, method notifyAll, method notify, method clone, method getClass, method hashCode, method toString, method equals, method wait, method wait, method wait, method finalize, method asInstanceOf, method isInstanceOf, method !=, method ==)

scala> typeOf[TupleReflection].members.view.filter(_.isValue).filter(!_.isMethod).toList
res16: List[reflect.runtime.universe.Symbol] = List(value tuple)

I found a way but it's not pretty.

class TupleReflection(@(specializedFor @field)(Array(classOf[Int], classOf[String]) val tuple: Tuple2[Int, String])

I created the annotation specializedFor with runtime retention policy. It receives an Array of Class[_]. That way I can find in runtime exclusively with reflection the types of the Tuple2 field.

It's unsafe because I can't test that the Array contains the same types as the Tuple2.

In my API I have to first check if the annotation is present and if it is force the genericTypes to be those.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!