Java Forum / General / April 2006
Reflecting generics
Domagoj Klepac - 31 Mar 2006 13:57 GMT I'm wondering if this is possible - and after much digging, it seems that it isn't. I have the following piece of code:
ArrayList<String> stringArray = new ArrayList<String>(); Class c = stringArray.getClass();
Is it possible to, somehow, get "java.lang.String" from c? Or is that information lost after compiling?
Domchi
Adam Maass - 31 Mar 2006 15:10 GMT > I'm wondering if this is possible - and after much digging, it seems > that it isn't. I have the following piece of code: [quoted text clipped - 4 lines] > Is it possible to, somehow, get "java.lang.String" from c? > Or is that information lost after compiling? Generics are implemented by "type erasure." At runtime, any reference to "java.lang.String" is long-since gone, so it can't be returned by any reflective method.
-- Adam Maass
Domagoj Klepac - 31 Mar 2006 16:11 GMT >> I'm wondering if this is possible - and after much digging, it seems >> that it isn't. I have the following piece of code: [quoted text clipped - 8 lines] >"java.lang.String" is long-since gone, so it can't be returned by any >reflective method. Thought so. Adam, thanks for clarification.
Domchi
Tony Morris - 01 Apr 2006 00:55 GMT >> I'm wondering if this is possible - and after much digging, it seems >> that it isn't. I have the following piece of code: [quoted text clipped - 10 lines] > > -- Adam Maass Not quite. Consider a method that declares to return List<String> - call it m. You package that method up in a jar, and put it on yourjars.com. Fred downloads the jar, and places it on his compile-time classpath. He also writes a statement that invokes your method: List<Integer> l = yourType.m();
The compiler fails, since the method declares to return type List<String>. Not *all* information is lost to type erasure, and for the life of me, I cannot recall the details (and I'm too lazy to reference it). I'll leave the rest as a reader exercise :)
 Signature Tony Morris http://tmorris.net/
s/Commonwealth Games/Commonwealth Swimming
Dimitri Maziuk - 01 Apr 2006 01:15 GMT Tony Morris sez:
>> Generics are implemented by "type erasure." At runtime, any reference to >> "java.lang.String" is long-since gone, so it can't be returned by any >> reflective method. > > Not quite. ... Not *all* information is lost to type erasure, and for the
> life of me, I cannot recall the details (and I'm too lazy to reference > it). The details are related to the difference between "class" and "object" (hint: "runtime" in Adam's post is a dead giveaway) and if you don't remember them you probably should read an OO 101 text book before you try to program anything.
HTH Dima
 Signature Sufficiently advanced incompetence is indistinguishable from malice.
Tony Morris - 01 Apr 2006 06:25 GMT > Tony Morris sez: >>> Generics are implemented by "type erasure." At runtime, any reference to [quoted text clipped - 13 lines] > HTH > Dima No the details are not related to the difference between "class" and "object", but I still can't be arsed looking it up - even more so than before. It will likely be in one of the specs from my previous job that I have lying about.
In relation to OO, I am, and have been for some time now, proposing a formal invalidation of OO (fsvo) under a given set of axioms.
Excuse my refusal to engage in Usenet nonsense by returning the foolish remark.
 Signature Tony Morris http://tmorris.net/
s/Commonwealth Games/Commonwealth Swimming
Timbo - 31 Mar 2006 15:35 GMT > I'm wondering if this is possible - and after much digging, it seems > that it isn't. I have the following piece of code: [quoted text clipped - 6 lines] > > Domchi Hmm... it appears that you can't. I would have thought that you could do the following:
Class<? extends ArrayList<String>> c = stringArray.getClass();
which would at least give you the compile-time type, but my compiler is complaining that the assignment:
Test.java:8: incompatible types found : java.lang.Class<capture of ? extends java.util.ArrayList> required: java.lang.Class<? extends java.util.ArrayList<java.lang.String>> Class<? extends ArrayList<String>> c = stringArray.getClass(); ^ Am I missing something here??
Dimitri Maziuk - 31 Mar 2006 18:04 GMT Timbo sez:
>> I'm wondering if this is possible - and after much digging, it seems >> that it isn't. I have the following piece of code: [quoted text clipped - 22 lines] > ^ > Am I missing something here?? No. I've just been through this exercise ("fun with generics" thread) and my conclusions are: 1. you can't really nest angle brackets, 2. you can't really use a specific type (incl. wildcard) inside angle brackets.
Dima
 Signature ... If you want to make sure you don't put a Pig in a List of airplanes and have it fail at insertion rather than extraction, use planelist.add((Airplane)o) instead of planelist.add(o). It's that easy. -- Mark 'Kamikaze' Hughes
Oliver Wong - 31 Mar 2006 18:39 GMT >> I'm wondering if this is possible - and after much digging, it seems >> that it isn't. I have the following piece of code: [quoted text clipped - 22 lines] > ^ > Am I missing something here?? The following code: <code> import java.util.ArrayList;
public class FillTest { public static void main(String args[]) { ArrayList<String> stringArray = new ArrayList<String>(); Class<? extends ArrayList<String>> c = stringArray.getClass(); } } </code>
Compiles fine for me on Eclipse 3.2M5.
- Oliver
Roedy Green - 31 Mar 2006 19:02 GMT On Fri, 31 Mar 2006 14:57:36 +0200, Domagoj Klepac <no.spam.sent.2.domchi@spamgourmet.com> wrote, quoted or indirectly quoted someone who said :
> ArrayList<String> stringArray = new ArrayList<String>(); > Class c = stringArray.getClass(); > >Is it possible to, somehow, get "java.lang.String" from c? >Or is that information lost after compiling? The way to do it would be to extend ArrayList where you pass the class of the contents as a constructor parameter. Then it would exist at run time.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Domagoj Klepac - 01 Apr 2006 12:04 GMT >> ArrayList<String> stringArray = new ArrayList<String>(); >> Class c = stringArray.getClass(); [quoted text clipped - 5 lines] >of the contents as a constructor parameter. Then it would exist at run >time. I don't have any control over the c - I just get tossed the instance of it (and it can be anything). After that I'm on my own, the only help coming from reflection.
If c is a String array, I might want to fill it with a list of Strings.
What I'm wandering right now is, if the c is an ArrayList of Strings, can I do the same. I can, but I have to know that ArrayList holds Strings or not.
Domchi
Piotr Kobzda - 01 Apr 2006 11:12 GMT > ArrayList<String> stringArray = new ArrayList<String>(); > Class c = stringArray.getClass(); > > Is it possible to, somehow, get "java.lang.String" from c? > Or is that information lost after compiling? If 'stringArray' is a field you can retrieve this info this way:
Field f = YourClass.class.getDeclaredField("stringArray"); Class c = (Class) ((ParameterizedType) f.getGenericType()) .getActualTypeArguments()[0];
This info is attached as the generic filed _signature_ in a class file. In a case of local variable this info could be retrieved as well using one of bytecode manipulation libraries, but you have to add the local variables debugging info into your class file (-g:vars compiler option).
piotr
Domagoj Klepac - 01 Apr 2006 12:04 GMT >> ArrayList<String> stringArray = new ArrayList<String>(); >> Class c = stringArray.getClass(); [quoted text clipped - 12 lines] >one of bytecode manipulation libraries, but you have to add the local >variables debugging info into your class file (-g:vars compiler option). Unfortunately, it's not a field - it's a method's return type. What I have is an instance of object (I don't know anything about this object) passed to my class at a runtime. Then I use reflection to find out if the object has a specific method. If it has, I get the return type of that method. If the return type extends Collection, I want to know if it's a collection of Strings or something else.
So basically, I'm at a point where I have a Method instance, and I can .getReturnType(), and I can find out if the return type implements Collection, but that's as far as I can get.
Domchi
Bjorn Abelli - 01 Apr 2006 12:21 GMT > Unfortunately, it's not a field - it's a method's return type. No problem, as long as the genericity is defined in the class. Example:
import java.util.*; import java.lang.reflect.*;
public class ReflectMethodGenerics {
public static void main(String[] args) throws Exception {
ReflectMethodGenerics rg = new ReflectMethodGenerics(); Class c = rg.getClass(); Method m = c.getMethod("GenericMethod"); Type t = m.getGenericReturnType();
Class x = extractType(t);
System.out.println(x); }
public ArrayList<String> GenericMethod() { ArrayList<String> s = new ArrayList<String>(); return s; }
private static Class extractType(Type t) { if (t != null && t instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) t; Type[] genTypes = pt.getActualTypeArguments();
if (genTypes.length == 1 && genTypes[0] instanceof Class) { return (Class) genTypes[0]; } else if (genTypes.length == 2 && genTypes[1] instanceof Class) { // TODO we might want to store the index type at some point return (Class) genTypes[1]; } } return null; } }
------------------------- However, if the method's return type isn't declared as the generic type, you can't get the parameterized type, as this also is valid...
public ArrayList GenericMethod() { ArrayList<String> s = new ArrayList<String>(); return s; }
// Bjorn A
Domagoj Klepac - 01 Apr 2006 12:46 GMT >> Unfortunately, it's not a field - it's a method's return type. > >No problem, as long as the genericity is defined in the class. Example: Many thanks! That's exactly what I've been trying to do.
>However, if the method's return type isn't declared as the generic type, you >can't get the parameterized type, as this also is valid... [quoted text clipped - 3 lines] > return s; > } I can live with that. :)
Domchi
Patricia Shanahan - 01 Apr 2006 15:48 GMT ...
> Unfortunately, it's not a field - it's a method's return type. What I > have is an instance of object (I don't know anything about this [quoted text clipped - 8 lines] > > Domchi Have you tried using getGenericReturnType instead of getReturnType? This program, when run with no command line arguments, prints "java.util.ArrayList<java.lang.String>". When run with an argument, it prints "class java.util.ArrayList".
import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.ArrayList;
public class GenericTest {
public static void main(String[] args) { Object o; if (args.length > 0) { o = new C1(); } else { o = new C2(); } Class c = o.getClass(); try { Method m = c.getMethod("myMethod", new Class[0]); Type t = m.getGenericReturnType(); System.out.println(t); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
class C1 { public ArrayList myMethod() { return new ArrayList(); } }
class C2 { public ArrayList<String> myMethod() { return new ArrayList<String>(); } }
Patricia
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|