Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / April 2006

Tip: Looking for answers? Try searching our database.

Reflecting generics

Thread view: 
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 Magazines

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

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.