I have a class with a field that is specialized and is using a raw datatype. For instance a Tuple2[Int, String]:
scala> class TupleReflection(val tuple: Tuple2[Int, String])
defined class TupleReflection
scala> val refl = new TupleReflection((5, "hello"))
refl: TupleReflection = TupleReflection@1a597ec8
I want to use reflection now to find out the type parameters of the Tuple2 inside my 'refl' instance. (I cheat a little using 'head' to get the field because I know it's the only one.)
scala> val field = refl.getClass.getDeclaredFields.head
field: java.lang.reflect.Field = private final scala.Tuple2 TupleReflection.tuple
Now that I have the field I can query the generic types.
scala> field.getGenericType
res41: java.lang.reflect.Type = scala.Tuple2<java.lang.Object, java.lang.String>
The problem now is that the first type is Object. Is there a way to know, via reflection alone, the real type (Int) of that parameter?
Update:
I'm using this in a context of automatic serialization within my own API. Given a class marked with @Serializable I can serialize it. To do so I must build a tree of the fields and types of the class recursively using reflection so I can do a deep serialization.
If I'm working directly with a @Specialized class it works because the types are explicit and known at compile time at the invocation site. If a field in the hierarchy is @specialized I have no way to tell via reflection. Querying the fields or methods declared in a class doesn't yield the correct value. The type is present in runtime but only on the instance held in the field, not on the declaration of the field itself. Thus if the instance is null and can't do a "getClass" I can't know the correct types by reflection alone.
I found a way but it's not pretty.
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.
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:
Update #1
The following function shows how you can get a type of an instance:
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