Reflecting on Generics
To quote the java.lang.reflect package docs (javadocs), "Reflection allows programmatic access to information about the fields, methods and constructors of loaded classes, and the use reflected fields, methods, and constructors to operate on their underlying counterparts on objects, within security restrictions."
Let me just say that I know it doesn't mention generics. It's weird for me too. But you'd expect it would be there, right?
Let us begin. The interface GenericDeclaration (javadoc) comes to describe any Type (javadoc) that can have generics declared on it.
As you'd expect, the class Class (java) (javadoc) implements this interface and it's single method, getTypeParameters. Unfortunately, this method returns only the declaration type. This is of course a result of a thing called Erasure, which is described here (search for "Behind the scenes").
Fine; I understand why Erasure is needed (and unlike what's said in this post, I do understand why it isn't backwards compatible). However, what should I do? While parsing classes in X2J (sourceforge), I need to retrieve the collection's declared type in order to know what type to instanciate when reading an XML file - And I can't, as this information is not stored in the Class instance (and nor in the .class file!)
My solution for now is to add another parameter to the @InnerElement annotation, but it doesn't seem like the best methodoligy..
Why it (dotNet's Generics) backwards compatible: If I'd change one of my inner modules to start using Generics (externally, anyway) in dotNet, I'd have to change an entire application. In Java it won't happen Because of erasure. That way, Sun could make a lot of their older classes generic while retaining backwards compatibility, while in dotNet they created a new namespace for their Collections, which has a different structure than the original (missing classes, different methods, etc). That way, switching to the generic type fo collections in dotNet wasn't as smooth, as they were different classes.
Let me just say that I know it doesn't mention generics. It's weird for me too. But you'd expect it would be there, right?
Let us begin. The interface GenericDeclaration (javadoc) comes to describe any Type (javadoc) that can have generics declared on it.
As you'd expect, the class Class (java) (javadoc) implements this interface and it's single method, getTypeParameters. Unfortunately, this method returns only the declaration type. This is of course a result of a thing called Erasure, which is described here (search for "Behind the scenes").
Fine; I understand why Erasure is needed (and unlike what's said in this post, I do understand why it isn't backwards compatible). However, what should I do? While parsing classes in X2J (sourceforge), I need to retrieve the collection's declared type in order to know what type to instanciate when reading an XML file - And I can't, as this information is not stored in the Class instance (and nor in the .class file!)
My solution for now is to add another parameter to the @InnerElement annotation, but it doesn't seem like the best methodoligy..
Why it (dotNet's Generics) backwards compatible: If I'd change one of my inner modules to start using Generics (externally, anyway) in dotNet, I'd have to change an entire application. In Java it won't happen Because of erasure. That way, Sun could make a lot of their older classes generic while retaining backwards compatibility, while in dotNet they created a new namespace for their Collections, which has a different structure than the original (missing classes, different methods, etc). That way, switching to the generic type fo collections in dotNet wasn't as smooth, as they were different classes.
Comments (4)
I've seen your post @ problogger, and was very suprised to see an israeli guy over there, i think i'm actually the first reader from Israel, started reading there on May...and was suprised from the lack of awareness about this blog in our state.
Well, let me introduce myself:
Allen Heat, from Carmel city in Israel, i hope that maybe in the future we'll have the chance to talk about blogging and money in hebrew :P
Heat
I accept your invitation. How do I get in contact with you?
The following chunk of code should get you the type of a collection from the getter method:
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) returnType;
Type actualType = actualType = ptype.getActualTypeArguments()[0];;
if (actualType instanceof Class) {
propertyClass = (Class) actualType;
}
}
-Tim Fennell
http://stripes.mc4j.org
I will start implementing it as soon as I finish with Arrays, which are much simpler (getCompoundClass() from their Class instance and that's it).
Thanks again!