Reflecting generics

D

Domagoj Klepac

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
 
A

Adam Maass

Domagoj Klepac said:
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?

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
 
T

Timbo

Domagoj said:
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

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??
 
D

Domagoj Klepac

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.

Thought so. Adam, thanks for clarification.

Domchi
 
D

Dimitri Maziuk

Timbo sez:
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??

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
 
O

Oliver Wong

Timbo said:
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??

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
 
R

Roedy Green

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.
 
T

Tony Morris

Adam said:
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

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 :)
 
D

Dimitri Maziuk

Tony Morris sez:
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
 
T

Tony Morris

Dimitri said:
Tony Morris sez:
... Not *all* information is lost to type erasure, and for the

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

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.
 
P

Piotr Kobzda

Domagoj 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?

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
 
D

Domagoj Klepac

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).

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
 
D

Domagoj Klepac

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.

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
 
B

Bjorn Abelli

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
 
D

Domagoj Klepac

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...

public ArrayList GenericMethod() {
ArrayList<String> s = new ArrayList<String>();
return s;
}

I can live with that. :)

Domchi
 
P

Patricia Shanahan

Domagoj Klepac wrote:
....
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

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

generics puzzle 57
LEETCODE 3 3
A problem regarding generics 13
Generics ? 14
Help on java generics 18
How to sort a CSV file with merge sort JAVA 7
Generics and for each 12
Another generics question: List<Class<?>> ls = ? 12

Members online

No members online now.

Forum statistics

Threads
474,431
Messages
2,571,679
Members
48,796
Latest member
Greg L.

Latest Threads

Top