Genericity improvement / Exact parameter type at runtime - Java SE (Archived)

For what reason you need something like that? Maybe one can find a more elegant way.
--
Best regards,
Thomas Singer

IMHO, classes are not sufficient for all solutions, T can be any (generic) type.
Syntactic suger proposal:
[code]    Type t = T.type[/code]
instead of:
[code]    Class cls = str.getClassParameter("T");[/code]
Access to the runtime type of a type parameter will require that the type parameters are passed into the constructor/method with each invocation of a generic constructor/method.

Related

Class of bound generics

When binding a generic class (hope that bind is the correct term), why can't one retrieve its class?
E.g.:
class Clazz {}
class Generic<T> {}While I can use the bound type Generic<Clazz> for conversion or instance creation, why does the following fail:
Generic<Clazz>.classThanks,
Stefan 
Since generics are done by erasure, there is no special Generic<Clazz> class. If you have this:
Generic<Clazz> generic = new Generic<Clazz>();
System.out.println(generic.getClass());It will print the same as if you had used the raw type, or used any other class as the parameter. The reason for this is again erasure, which means that the compiler turns:
Generic<Clazz> generic = new Generic<Clazz>();
Clazz test = generic.doStuff();
System.out.println(generic.getClass());into
Generic generic = new Generic();
Clazz test = (Clazz) generic.doStuff();
System.out.println(generic.getClass()); 
Thanks. I assumed it has to do with erasure. So the only way to do assure type safe factoring like
Generic<Clazz> generic = produce(Generic<Clazz>.class);would be to do instead
Generic<Clazz> generic = (Generic<Clazz>) produce(Generic.class);and suppress the warning and possibly catch cast exceptions.
Am I right? 
Thanks. I assumed it has to do with erasure. So the
only way to do assure type safe factoring like> Generic<Clazz> generic = produce(Generic<Clazz>.class);I'm not sure what you mean by type safe.
Even without erasure, you have no way to know if
Generic<Class> has the required constructor.
Reflection provides means to bend the rules
of a static type system. This means that you
can't expect static type safety from a reflection
based solution.
The Java VM preserves runtime type safety
but slightly askew from the static type system
provided by generic types. 
Sorry, I mixed up two thoughts, so it got to complicated ;)
Let's say I have a properties container that stores property objects at names. To not have to rewrite checking code and suppress unchecked conversion for correctly returned types each time retrieving a property object, I use a method like:
<T> T getProperty(Class<T> clazz, String name, T defaultT);which casts to T, catches cast exceptions, and returns default, if failed to retrieve a proper property. Unfortunately, this does not work with bound generics so I have to do the type checking again. Which is no big deal, as one simply can add another method to the properties container. Just, I was curious, if I had overseen a more elegant way, and I was unsure, if my understanding of erasure was correct.
Thanks anyway :) 
Sorry, I mixed up two thoughts, so it got to
complicated ;)
Let's say I have a properties container that stores
property objects at names. To not have to rewrite
checking code and suppress unchecked conversion for
correctly returned types each time retrieving a
property object, I use a method like:> <T> T getProperty(Class<T> clazz, String name, T defaultT);which casts to T, catches cast exceptions, and
returns default, if failed to retrieve a proper
property. I trust that finding the proper property only depends
on the string, not the type?
Unfortunately, this does not work with
bound genericsIt doesn't work with most parameterized types, yes.
However, in certain cases you can work around that:
Instead of using ArrayList<String> you can use
class StringList extends ArrayList<String> { ... }This class has all type information available at runtime.
I know this doesn't work in the most general cases, but
perhaps you might find this trick handy.
Also, sometimes Collections.checkedList, etc might
be handy.
so I have to do the type checking again.I'm not sure what you mean by type checking. Once
you store something in your properties container,
you loose the static information which allows
the compiler to statically check your program.
This is why you insert casts.
In the most general case, I don't see how you can
check this at runtime at all. If you don't know anything
about the clazz parameter, you can at most do this:
#SuppressWarnings("unchecked")
public static <T> T uncheckedCast(Object o) {
     return (T)o;
} 
I trust that finding the proper property only
depends
on the string, not the type?Yes. I use Map<String, Object> as property container, as I do not know about the objects' classes.
Instead of using ArrayList<String> you can useclass StringList extends ArrayList<String> { ... }I did so in some cases, unfortunately this would cause to replicate code in my application, that is able to handle, say, instances of ArrayList<T> inside an ArrayListMediator<T> class.
so I have to do the type checking again.I'm not sure what you mean by type checking. OnceSorry, I meant the class conversion, which is necessary to do for generic types. With my above method, that would be:
Generic<Clazz> generic = (Generic<Clazz>) getProperty(Generic.class, name, defaultGeneric);unless I allow to access the Map directly.
Hence, getProperty casts to Generic and for Compile-time type safety I do a cast to Generic<Clazz>.
(Makes me wonder, if the compiler will remove the cast, as getProperty already returns the runtime class Generic.) 
Sorry, I meant the class conversion, which is
necessary to do for generic types. With my above
method, that would be:Generic<Clazz> generic = (Generic<Clazz>) getProperty(Generic.class, name, defaultGeneric);unless I allow to access the Map directly.
Hence, getProperty casts to Generic and for
Compile-time type safety I do a cast to
Generic<Clazz>. That doesn't give you compile time type safety. Even if
the compiler could implement the check it could still
fail. All you're doing is tell the compiler: "trust me," that
is not the same as static type safety ;-)
(Makes me wonder, if the compiler will remove the
cast, as getProperty already returns the runtime
class Generic.)You're right. The compiler would be just as happy with this:
Generic<Clazz> generic = getProperty(Generic.class, name, defaultGeneric);The compiler makes an unchecked conversion from Generic to
Generic<Clazz>. This is exactly as type safe (or not) as your
cast. You also get a warning which is unavoidable. 
That doesn't give you compile time type safety. Even
if
the compiler could implement the check it could
still
fail. All you're doing is tell the compiler: "trust
me," that
is not the same as static type safety ;-)Well, of course, only for the following code. If there is a problem with the "real" type, at least I know where to look for the cause ;)
Thanks a lot.

Get the Type of a generic field at runtime, How to?

Hello,
As the topic already says, i need to get the Type of a particular field of a class. This field is declared private and generic. In C# there is a method
Type Object.getTypeIs there any specific way to do this in Java 1.5?
Please excuse my poor english.
Thanks in advance.
Markus 
As I understand it, you have a generic field like
private List<String> myList;If you want to know the actual object type (e.g. ArrayList), you can use getClass() provided by Object:
myList.getClass()If you want to know the parametrized type (String in the example), I think there is no way of knowing this in Java 1.5 or Java 1.6, since the parametrized type is erased and not available at run time. 
If you want to know the parametrized type (String in the example), I think there is no way of knowing this in Java 1.5 or Java 1.6, since the parametrized type is erased and not available at run time.The type of a parameterized field is not erased. You can retrieve the information like this (barring any typos):
Type type = myClass.getField("myList").getGenericType();
if(type instanceof ParameterizedType)
{
   Type parameterType = ((ParameterizedType)type).getActualTypeParameters()[0];
   System.out.println("Got it: "+parameterType); // Should print "java.lang.String";
} 
McNepp wrote:
If you want to know the parametrized type (String in the example), I think there is no way of knowing this in Java 1.5 or Java 1.6, since the parametrized type is erased and not available at run time.The type of a parameterized field is not erased. You can retrieve the information like this (barring any typos):Correcting for the typos (since it interested me.)
public List<String> myList;
Type type = myClass.getClass().getField("myList").getGenericType();
if(type instanceof ParameterizedType)
{
   Type parameterType = ((ParameterizedType)type).getActualTypeArguments()[0];
   System.out.println("Parameter: "+parameterType);
   System.out.println("Class: "+((Class)parameterType).getName());
}
// Output:
Parameter: class java.lang.String
Class: java.lang.StringNotice that myList is public. getField() won't work (as is) with private. 
That is very interesting. I just assumed no type information was ever retained. Is there any other way to get a ParameterizedType instance? I tried for a while doing it with Class, but that did not seem to pay out.
Thanks,
- Saish 
McNepp wrote:
If you want to know the parametrized type (String in the example), I think there is no way of knowing this in Java 1.5 or Java 1.6, since the parametrized type is erased and not available at run time.The type of a parameterized field is not erased.For most intents and purposes, it is. Type erasure refers to the fact that at runtime, there are not actually multiple class binaries depending on the generic arguments to a class. Therefore, an ArrayList<T> is actually just an ArrayList with no generics.
The fact that this (very limited) information is available at run-time is basically due to some metadata contained in the Class object, determined at compile-time. That's why it can only work with declarations, not with actual run-time Objects. That's also why if you assigned, for example, an ArrayList<Number> to a List<?> myList, there would be absolutely no way of obtaining the fact that myList contains an ArrayList<Number>. You could only ever learn that it contains an ArrayList.
Heck, it can barely tell you anything:
public class TypeErasure<T> {
   public List<T> myList = new ArrayList<T>();
  
   public static void main(String... args) throws Exception {
      TypeErasure<String> te = new TypeErasure<String>();
      Type type = te.getClass().getField("myList").getGenericType();
      if(type instanceof ParameterizedType)
      {
         Type parameterType = ((ParameterizedType)type).getActualTypeArguments()[0];
         System.out.println("Parameter: "+parameterType);
      }
   }
}
//prints: "Parameter: T" 
Heck, it can barely tell you anythingI experienced the same. Pity. It would be nice to inspect them at run-time.
- Saish 
endasil wrote:
McNepp wrote:
If you want to know the parametrized type (String in the example), I think there is no way of knowing this in Java 1.5 or Java 1.6, since the parametrized type is erased and not available at run time.The type of a parameterized field is not erased.For most intents and purposes, it is. Type erasure refers to the fact that at runtime, there are not actually multiple class binaries depending on the generic arguments to a class. Therefore, an ArrayList<T> is actually just an ArrayList with no generics. Frankly, I don't understand why you insist that the information on generic fields that the OP was asking about is lost at runtime.
What you write about instances of generic classes losing their type information is of course correct, albeit not to the point of the original question.
The original question was about how to obtain the type of a generic field.
The compiler preservers this information in the class file, so it can be obtained at runtime. Frameworks like JPA put this to use extensively, proving that it is of real value. 
#McNepp: I agree. I think the information is useful enough, I wish we could have generic types stored more systematically. :^)
- Saish 
McNepp wrote:
endasil wrote:
McNepp wrote:
If you want to know the parametrized type (String in the example), I think there is no way of knowing this in Java 1.5 or Java 1.6, since the parametrized type is erased and not available at run time.The type of a parameterized field is not erased.For most intents and purposes, it is. Type erasure refers to the fact that at runtime, there are not actually multiple class binaries depending on the generic arguments to a class. Therefore, an ArrayList<T> is actually just an ArrayList with no generics. Frankly, I don't understand why you insist that the information on generic fields that the OP was asking about is lost at runtime.I wasn't trying to insist that. At the time, I was replying more to Saish and trying to reaffirm that most information about generics is lost at run-time. I mistakenly ignored how you qualified it with "field."
What you write about instances of generic classes losing their type information is of course correct, albeit not to the point of the original question.Nope, you're right. I was just trying to reconcile the fact that many people get confused that there's any information available at run-time, and so start down the path of thinking that type erasure doesn't exist. But it very much does.
The original question was about how to obtain the type of a generic field.And I did show in my example that even that is fairly limited, given that if the type is provided by the parameter of the class, it doesn't give you anything useful (I'm not trying to say you said it would!).
The compiler preservers this information in the class file, so it can be obtained at runtime. Frameworks like JPA put this to use extensively, proving that it is of real value.Definitely. However I don't see this having as much to do with generics as basic reflection functionality. If you can get the type of a field at run-time, you should be able to get the parameters as well! That should in no way belittle its value, though. But I would have guessed (knowing little about) that JPA wouldn't put that to use so much as the type parameters of an accessor return type or mutator argument type. Especially since I thought we'd shown that you would need your fields to be non-private for JPA to be able to gain information about their type.
Edit: getDeclaredField works fine with private members, and returns the expected "java.lang.String" from jschell's example above
Edited by: endasil on 28-Apr-2009 10:39 AM

Here's a Crazy One: ClassifierMap

Hello, all. I have a task to perform that I think Generics are incapable of handling; I'm hoping someone can prove me wrong. I'm trying to write a generalized means of expressing what I'm about to describe, so bear in mind that I can't just solve this by hard-coding the types. (Or rather I can but I'm aiming higher.)
I have a set of objects which are of type S. S accepts a parameterized type T. I would like to map each of S by its type T in order to be able to look it up by the type it accepts. (I recognize that, because this information is unavailable at runtime, my class will need to suppress some unchecked warnings; this is acceptable as long as I can encapsulate the functionality properly.)
So an example usage of this is:
ClassifierMap classifierMap = new ClassifierMap<FooListener<?>>();
...
FooListener<BarEvent> listener = ...;
classifierMap.put(BarEvent.class, listener);
...
FooListener<BarEvent> listener2 = classifierMap.get(BarEvent.class);My problem is that I can't seem to come up with a method declaration that can actually enforce type safety when the object in question is stored. Please bear in mind that I would like FooListener to be parameterized. The issue at hand seems to be that it's impossible, even at compile time, to discriminate between parameterized types based on their parameterized types. That is, I have no way of declaring that the parameterized type "FooListener<?>" is a single-parameter type so that I can enforce a behavior on it like
public class ClassifierMap<S>
{
    public void <T> put(Class<T> type, S<T> value) { ... }
}Have I properly expressed myself? Anyone have any ideas?
Thanks! 
ClassifierMap classifierMap = new ClassifierMap<FooListener<?>>()The first problem is right here. The LHS declares a variable of the raw type, so you can't possibly get any generic behaviour out of it. 
Ah, yes indeed. A rather elementary mistake, of course; it's merely a typo I made in transcribing my problem. Any ideas as to the meat of it, though? I can't come up with a legal way to write the method declaration because it seems that Java lacks a mechanism for parameterizing something other than the innermost parameter. If that makes sense. 
tvynr wrote:
Have I properly expressed myself? Anyone have any ideas?I don't think I understood what you are aiming at. Is S a type or a type parameter? If the latter, is it arbitrary or does it have a bound (which may be parameterized)? What do you mean by "accepts a parameterized type"?
Generics only are useful for compile-time type safety. If you target type safety at runtime, Generics is the wrong choice of mechanism. 
I think the mechanism I want is based on compile-time typing; In this instance, I want an assurance that I'm receiving the appropriate type of listener for a given event type. So my listener class S would be something like
public interface FooListener<T extends BarEvent>
{
    public void handle(T event);
}The idea, then, is that an event handling mechanism could simply be
public void <T extends BarEvent> dispatchEvent(T event)
{
    FooListener<T> listener = classifierMap.get((Class<T>)event.getClass());
    listener.handle(event);
}This, of course, leads to the further unfortunate scenario that I have to cast the output of event.getClass(), since getClass() returns Class<?> (or,, more specifically, Class<? extends T>, I think).
What I really want is a compile-time type safety mechanism which will allow me to associate a listener that listeners for a given type of event with the event type for which it listens. I would also like the output of said class to give me a properly parameterized result. This would be easy enough, but there is another portion of my application which contains a number of serializers which convert between a given type and String. Given that both of these mechanisms (registering listeners by event class and registering serializers by target class) are pretty much identical, I wanted to create a single class which would address both issues. But that class would need to accept as a parameter what I'm giving it (the listener or the serializer) and understand that whatever I give it has a parameterized type. And I'm getting the impression that that's not possible in Java. 
tvynr wrote:
This, of course, leads to the further unfortunate scenario that I have to cast the output of event.getClass(), since getClass() returns Class<?> (or,, more specifically, Class<? extends T>, I think).Because the compiler has no idea, if the class returned really is T or a subtype of T.
As I assume that you have control over the event types, why don't you let it return some type information instead of using getClass()?
Maybe Neal's [super type tokens|http://gafter.blogspot.com/2006/12/super-type-tokens.html] give a hint on how this could be solved. It does not apply to your constellation directly, though. I think, you could have a token on the parameterized FooListener. 
stefan.schulz wrote:
tvynr wrote:
This, of course, leads to the further unfortunate scenario that I have to cast the output of event.getClass(), since getClass() returns Class<?> (or,, more specifically, Class<? extends T>, I think).Because the compiler has no idea, if the class returned really is T or a subtype of T.Ah. So you're getting at something like
classifierMap.<Bar1Event>get(myBar2Event)where Bar2Event extends Bar1Event?
As I assume that you have control over the event types, why don't you let it return some type information instead of using getClass()?'cause then I'm writing boilerplate code into my event model to do the stuff that I expect the existing type system to do for me. Ignoring this particular application of the idea, I'm trying to somehow generalize the idea of creating a mapping between Class<T> and S<T> where S is a parameter specified on construction of the object and T is a parameter which is unique to each call. But I can't seem to come up with a way to express to Java the type parameter S.
Perhaps my issue is that there is no way to express the constraint I want. If you define a type S, you can put inheritance constraints on it (S extends Bar) but I don't know of any way of constraining its form in terms of parameterization (i.e., "S has a type parameter T and T extends Bar").
Maybe Neal's [super type tokens|http://gafter.blogspot.com/2006/12/super-type-tokens.html] give a hint on how this could be solved. It does not apply to your constellation directly, though. I think, you could have a token on the parameterized FooListener.I'll take a look and post back; thanks for the link! 
tvynr wrote:
'cause then I'm writing boilerplate code into my event model to do the stuff that I expect the existing type system to do for me. Ignoring this particular application of the idea, I'm trying to somehow generalize the idea of creating a mapping between Class<T> and S<T> where S is a parameter specified on construction of the object and T is a parameter which is unique to each call. But I can't seem to come up with a way to express to Java the type parameter S.I'm not sure if it is boilerplate. Using reflection is usually no good way to solve a problem.
Perhaps my issue is that there is no way to express the constraint I want. If you define a type S, you can put inheritance constraints on it (S extends Bar) but I don't know of any way of constraining its form in terms of parameterization (i.e., "S has a type parameter T and T extends Bar").No, you can't. But you could use a parameterized bound, i.e., some interface Foo<T> that is the upper bound of S, and declare both, T and S, or use wildcards, if applicable.

reflection api to be able to provide generics information?

in the recent online chat
http://developer.java.sun.com/developer/community/chat/JavaLive/2003/jl0729.html
Josh Bloch says this:
Josh Bloch: The reflection APIs are indeed being extended to handle
enums, and generics and annotations as well:)this is really confusing, since I thought all generic information was lost at compile-time. (experiments with the prototype compiler seemed to confirm this too)
i read the docs/papers available, and this seemed to confirm my first point of view ("type-erasure")
thanks,
asjf
What is erased is the dynamic type of the type parameters of instances
of generic classes. What will be available through reflection is the
type parameters and bounds of the declared entities (classes, fields,
etc).
So, for example, in the class
class Foo<X extends Number> {}You can discover that the type parameter of Foo is named X and that its bound is Number. There is no way to get the actual type parameters of an instance of a generic type. For example, in
Object x = new Foo<Integer>();There is no way to get the actual type parameter of the instance assigned to x.

Class.getConstructor(Class... parameterTypes)

Hello,
Regarding Class.getConstructor(Class... parameterTypes):
The API documentation say: The constructor to reflect is the public constructor of the class represented by this Class object whose formal parameter types match those specified by parameterTypes.
What if one of the formal parameter types were an interface and the corresponding specified parameter type implements it. In this case the specified parameter type would not match the interface but the fact that it implements it makes it eligible for a match.
For example. if you specify java.awt.BorderLayout.class and the formal parameter type is the interface java.awt.LayoutManager. What would you do to make Class.getConstructor() return this constructor ? 
Send it the interface. 
As in:
Constructor<Panel> c = Panel.class.getConstructor(LayoutManager.class);
System.out.println(c);
Panel p = c.newInstance(new BorderLayout());
System.out.println(p); 
As in:
Constructor<Panel> c = Panel.class.getConstructor (LyoutManager.class);
System.out.println(c);
Panel p = c.newInstance(new BorderLayout());
System.out.println(p);You are right but I am afraid it will be more complex than that
I am running in a dynamic environment where neither the class nor its parameter types are known until run-time. To make it worse, The formal parameter types will not be known unless you do the following:
1. Get all constructors of the class.
2. For each constructor that has the same number of parameters you compare the specified parameter types with that constructor's parameter types until you hit a mismatch.
3. For each mismatch, if the formal parameter type is an interface and the specified parameter type implements it you use the formal parameter type instead.
I just wanted to avoid all this by calling a ready-made JDK method that does that for me (if there is one of course) 
if I need to find out if interface A is a superinterface of interface B, I think I should use isAssignableFrom(). I used A.isAssignableFrom(B) but it gave me unchecked warning !!! 
... 
Hello everyone,
Eventhough A.isAssignableFrom(B) causes a checked warning, it produces the right results. I just want to get rid of the warning.
Please help 
I am running in a dynamic environment where neither
the class nor its parameter types are known until
run-time. To make it worse, The formal parameter
types will not be known unless you do the following:
1. Get all constructors of the class.
2. For each constructor that has the same number of
parameters you compare the specified parameter types
with that constructor's parameter types until you hit
a mismatch.
3. For each mismatch, if the formal parameter type is
an interface and the specified parameter type
implements it you use the formal parameter type
instead.Why is this necessary? This sounds like something where a redesign might avoid the necessity of using reflection altogether. 
Why is this necessary? This sounds like something where a redesign might avoid the necessity of using reflection altogether.I want to execute a class at runtime. I first get the right constructor (based on the parameter types) and then use newInstance() to execute it. How can I avoid reflection in this case ??? 
One doesn't execute a class, one instantiates it and executes its methods.
Anyway, you might not need to use reflection at all. Whatever these classes are, they're going to have something in common that you're going to execute, right? You're not instantiating random classes and then executing random methods, right?
Whatever this thing is that you're executing, perhaps you can put it into an interface. Then you just execute the method specified in the interface, with no reflection needed. For finding the right constructor...maybe you can give each class a static factory method. It depends on what you're doing. But generally, I find that when reflection seems at first to be necessary, after a little more thought reflection can be avoided by redesigning the type hierarchy. 
One doesn't execute a class, one instantiates it and executes its methods.You are definitly right, execuse my java language, thank you ...
Now, don't be surpsized, I am instantiating random classes and executing random methods. These classes and methods are the Swing classes and methods, which I have no control over. I need to give the facility to execute any Swing class or method at run-time. It might sound a bit strange but it is a requirment. I thought that reflection is my only option ???
Thank you 
I guess "random" in the sense of "arbitrary"...
Are you trying to write a system that takes a textual description of a UI and then builds the UI at runtime, or something? 
All swing components are beans. As such they MUST have a default constructor. Call that to create the instance then use the bean naming scheme to figure out which methods to call to set it up correctly.
see http://java.sun.com/products/javabeans/
look at the JAF fro more info about figuring out the abilities of the bean.
You may also want to consider using a standard bean container that can do much of this work for you
matfud

Categories

Resources