Java: fetching generic class parameters at runtime - java

I have two classes, one abstract, one concrete:
abstract class Generator<T>;
class ConGenerator<T extends Complex<Z,Y>, Z extends Something1, Y extends Something2> extends Generator<T>;
Due to change in the number of parameters (I think), I cannot get the parameter classes at runtime using the usual approach with ParametrizedType, i.e.
ParameterizedType genericSuperclass = (ParameterizedType)getClass().getGenericSuperclass();
Type[] type = genericSuperclass.getActualTypeArguments();
All I am getting is the name I used for the param, T. I would appreciate any help in tackling this problem, I have already searched the web and used some libraries other people wrote for such problems; no luck so far.

The Problem
It is not always possible to infer type parameters given the runtime class, and yours is such a case. The root problem is that all instances of a generic class (irrespective of their type parameters) share the same runtime class, i.e.:
new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass()
Therefore, it is impossible to discover the type parameters given just the runtime class, if that class is generic and different instances of that class can use different values for the type parameter. (Yes, we can find the type parameter for class X<T extends String>, because String is final, are therefore the only possible argument. Likewise, we can find the type parameters of List if we know the runtime class is class MappedList<T> implements List<String> { ... }).
In contrast, it is always possible to infer the type parameters of a super class if the runtime class is not generic - that's what all those libraries and code examples floating around the net do with various degrees of sophistication. For instance, if you have:
class StringArrayList extends ArrayList<String> { ... }
you can discover that the type argument to ArrayList is String. This also works with anonymous classes (as long as they are not generic), because:
new ArrayList<String>() {}.getClass() != new ArrayList<Integer>() {}.getClass()
but fails with generic classes such as
ArrayList<T> makeList(T t) {
return new ArrayList<T>(t) {};
}
because
makeList("2").getClass() == makeList(2).getClass()
The Solution
If you need the type at runtime, you will need to provide it by other means, typically by passing the Class object to the constructor. You can also use a super type token (an instance of a non-generic, usually anonymous, subclass of the desired type, which allows you to discover type parameters by reflection). This has the advantage that type parameters that are themselves generic can be expressed, too.
If you only need the class for a particular thing, there may be simpler alternatives. For instance, if you simply need to create new instances of the type parameter, a factory (method) pattern is quite a bit simpler :-)

Related

Class<T> will also do type erase at runtime, without type information how can reflection work?

public <T> T genericMethod(Class<T> tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
Object obj = genericMethod(Class.forName("com.test.YourClass"));
This is a typical code for java to use generic method return an instance of specific class.
Instance of Class is pass as an variable and new instance is created by calling the constructor through reflection.
I am still confused by the mechanism of reflection and Class class.
My question is, if the class information of YourClass will be erase from the Class
instance, when calling the reflection method, why it can create an YourClass but not an object?
Shouldn't an Object be created?
Class<T> is a special type where the instances of that type that actually hold information about T, and the runtime can obtain the type information from the instance. But that's the only type that does so! For any other type, e.g. List<T>, instances of the type do not have any knowledge about T (because the purpose of List is different: to contain a sequence of objects of any type - the restriction that it only can hold T is enforced by the compiler but not by the runtime). In those situations, the instance can't tell the runtime anything useful about T.
"Type erasure" refers to the fact that the generic type parameter is erased from the instance's type during compilation, so a value that in the source code appears as List<T> appears as just List at runtime. The same holds for Class<T>, which appears as Class at runtime, but again, the instance itself knows what class T is because that's one of the purposes of the Class type.
Generics in Java is a huge hack that - quite impressively - they managed to implement only in the compiler. You can circumvent the compiler's checks by using reflection: for example, you could reflectively call add(x) on a List<String> strings where x is an Integer, and it will work because the instance is actually just a List that will accept values of any type. So now you have a List<String> where one element is an Integer! When you later try to do strings.get(i) (where i is the index you added the integer at), the implicit type cast to String that is inserted by the compiler is going to blow up.

Java generics - When is ? wildcard needed

Say you have some class with type T:
class MyClass<T extends SomeOtherClass> {
....
}
Now, you want to store instances of this class into a collection, but you don't really care about the type. I would express this as following:
private final List<MyClass> entries = new ArrayList<>();
Is there any good reason/advantage to write the following instead?
private final List<MyClass<?>> entries = new ArrayList<>();
Or even:
private final List<MyClass<? extends SomeOtherClass> entries = new ArrayList<>();
I myself can only find a bad reason to do this: whenever the type definition of MyClass changes (for example addition of another type), you have to alter the List<MyClass<?>> or List<MyClass<? extends SomeOtherClass>> definitions all over your code as well.
update
To update my question:
Why isn't the compiler to be able to track the type(s) of MyClass when your write List<MyClass> (or even List<MyClass<? extends SomeOtherClass>>)? He knows that MyClass is defined as MyClass<T extends SomeOtherClass>, so why isn't he able/allowed to do that when you write List<MyClass>?
In other words, why is List<MyClass> not equal to List<MyClass<?>> (or even List<MyClass<? extends SomeOtherClass>>)? The compiler has all the information to make that conclusion himself, afaik.
The ? wildcard is useful when you don't need to refer to the type again and so you don't need to make a specific identifier.
Your first snippet starts with class MyClass<T extends SomeOtherClass>. This is necessary when T is important later on, perhaps to declare a field argument, or return type. For example:
class MyClass<T extends SomeOtherClass> {
private final List<T> aListOfT;
public T getSomething() {
return this.aListOfT.get(0);
}
Since MyClass is a generic type, all references to it should be qualified to avoid avoidable runtime errors. Thus when you declare List<MyClass> you get a compiler warning that you use the raw type MyClass. If you don't care at that location in the code what sort of type MyClass is qualified with, then you use the ? to tell the compiler that you don't care and let it track the type and check all operations for validity.
Your first declaration means, you are not giving any information about your generic data for the future reflection systems, could be used by plugins, which are written for your main program.
The second declaration tells them, that the field contains an Object generics.
The third one is the more specific, it means, that the reflection systems knows, what is this field about detailly.
Using the first type, java will assume that the generic type is Object. The reason for this is, that generics were introduced in version 1.5. Before then the collection-classes stored everything as an object. For compatibility reasons giving no generic parameter means that you are using object.
The second type simply says you don't know or don't care what type it is. This information is preserved when the code gets compiled. So other programmer who might use your code would know that you don't care.
Because of java's type-erasure, there is no difference between these two at runtime.
With the last form you say:
I don't care what it is, but it has to be SomeOtherClass or a derivated type. Which is the same as:
List<MyClass<SomeOtherClass>>
You can also do it the other way around:
List<MyClass<? super SomeOtherClass>>
says that you don't care what type it is, unless it is a supertype of SomeOtherClass.

Access generic types of an object at runtime

I know how to access generic types of fields using reflection: Just check if field.getGenericType() instanceof ParameterizedType.
But how can one check the same for an arbitrary object, not knowing where it was declared?
Generics apply to variable declarations, method return types, etc., not objects per-se. You can determine whether the Class of a particular object uses generics via myObj.getClass().getTypeParameters() but you can't determine what values of those type parameters the specific object instance was created with.
Objects do not store generic information per se, so the bytecode generated for new ArrayList<Integer>() is exactly the same as the one for new ArrayList<String>(). I mean exactly. This is what is called type erasure of Java generics. They are just desugared to new ArrayList().
But, in almost all other situations, type parameters are retained, like field/parameter/return type declarations. One of the cases that is retained and not erased is the super class of a class. So if you create a class that extends ArrayList<String> you can access that information at runtime.
But this seems overkill, doesn't it? A new class that extends ArrayList<String> and another one that extends ArrayList<String>, etc. seems impractical. Anonymous inner classes can make this much easier. So, if you want to keep the generic information, you just do new ArrayList<String>() {} instead of new ArrayList<String>(). You can call getClass().getGenericSuperclass() on the created object to get the generic info.

What does the generic nature of the class Class<T> mean? What is T?

I understand generics when it comes to collections. But what does it mean in the case of the Class<T> class? When you instantiate a Class object, there's only one object. So why the T parameter? What is it specifying? And why is it necessary (if it is)?
Type parameter <T> has been added to java.lang.Class to enable one specific idiom1 - use of Class objects as type-safe object factories. Essentially, the addition of <T> lets you instantiate classes in a type-safe manner, like this:
T instance = myClass.newInstance();
Type parameter <T> represents the class itself, enabling you to avoid unpleasant effects of type erasure by storing Class<T> in a generic class or passing it in as a parameter to a generic method. Note that T by itself would not be sufficient to complete this task2: the type of T is erased, so it becomes java.lang.Object under the hood.
Here is a classic example where <T> parameter of the class becomes important. In the example below, Java compiler is able to ensure type safety, letting you produce a typed collection from a SQL string and an instance of Class<T>. Note that the class is used as a factory, and that its type safety can be verified at compile time:
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;
}
Since Java erases the type parameter, making it a java.lang.Object or a class specified as the generic's upper bound, it is important to have access to the Class<T> object inside the select method. Since newInstance returns an object of type <T>, the compiler can perform type checking, eliminating a cast.
1 SUN Oracle has published a good article explaining all this.
2 This is different from implementations of generics without type erasure, such as one in .NET.
3 Java Generics tutorial by Oracle.
The answer by dasblinkenlight already demonstrated one of the main uses of this parameter. There is one more aspect I consider relevant: using that parameter, you can restrict the kind of class you want to pass at a given location. So e.g.
Class<? extends Number> cls
means that cls may be any class implementing the Number interface. This can help catching certain errors at compile time, and makes class argument requirements more explicit.
Perhaps a comparison to the case without generics is in order
// Java ≥5 with generics // Java <5 style without generics
Class<? extends Foo> c; Class c;
Foo t1 = c.newInstance(); Foo t1 = (Foo)c.newInstance();
Object obj; Object obj;
Foo t2 = c.cast(obj); Foo t2 = (Foo)c.cast(obj);
As you can see, not having T as an argument would require a number of explicit casts, as the corresponding methods would have to return Object instead of T. If Foo itself is a generic type argument, then all those casts would be unchecked, resulting in a sequence of compiler warnings. You can suppress them, but the core issue remains: the compiler cannot check the validity of these casts unless you properly use the type argument.
In Java there's a single metaclass: Class. Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.
The use of generics in the Class type is top define the type of class. If I have ' Class obj' my object obj can holds only children of Charsequence.
This is an optional argument. I'm often put an '?' to avoid warnings from the Eclipse IDE if I don't need an specific type of class.

Generics: Get name of instance

I have a method which returns a List<Property<?>>.
Property is a type having one generic parameter:
public class Property<T extends Comparable<T>> { ... }
Having a list of mixed-typed properties, I cannot know what type parameter a specific element has.
I would like to do something like that:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
// I know this doesn't exist ----^
}
In one sentence: I need the PropertyWrapper to have the same generic template argument as the current Property does. Is there any way to do this?
I could apply a suggestion as stated in https://stackoverflow.com/a/3437930/146003 but even if I do this, how to instanciate the appropriate PropertyWrapper<XXX> then, only having an instance of Class<T>?
I can modify Property<?> if required. I also don't mind if reflection needs to be used (I assume it needs to be)
EDIT: I forgot something. In fact I cannot instanciate the wrapper by the line
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
because I have specialized subclasses (PropertyWrapper_String).
Now I see two possibilities:
1: Instanciate the class by string:
String strGenericType = "";
Class<?> wrapperClass = Class.forName("PropertyWrapper_" + strGenericType);
2: Is there any way to specialize a generic class without creating a subclass?
Many thanks in advance for your tips
Try creating the following method:
<T> PropertyWrapper<T> createWrapper(Property<T> property){
return new PropertyWrapper<T>(property);
}
Then call it as such.
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = createWrapper(crt);
}
The reason the above works is that the generic type T is inferred from the argument and is locked down for the entire method. Unlike using <?> in the loop where each instance of <?> is inferred to be a different type.
Edit:
To deal with the issue of having a different class type depending on the class in the wrapper, consider a Map where the key is the class being wrapped and the value is the wrapper.
Map<Class<?>, Class<?>> myMap;
Then you could so something like this:
Class<?> wrappedType = property.getGenericType();
Class<?> wrapperClass = myMap.get(wrappedType);
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) wrapperClass.newInstance();
Although you might need to do something like this if you need to pass an argument.
Constructor<?> constructor = wrapperClass.getDeclaredConstructor(property.getClass());
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) constructor.newInstance(property);
If you have a Class<T> you can just take that class, create an instance by calling newInstance() on the class object and cast it to T.
The problem you have is getting the generic parameter of crt. If you have concrete subclasses of Property, e.g. StringProperty extends Property<String>, you can get the type using reflection. However, if you only create instances of Property<T> without concrete subclasses and you don't know where the elements of the list are created, AFAIK it is impossible to get the generic type (even if you know where the elements are created it might be impossible though).
Thus, the only way you might get the property wrapper to know the type of the property might be to store the type parameter (the class) in the property itself. Then the wrapper could query the property for its type/class member variable.
Edit: some explanation on why this is impossible or at least very hard.
The problem with generics is that due to type erasure the generic type is lost when you create a property using new Property<SomeType>(). There's just no runtime information that you could use to retrieve SomeType here.
If you have concrete subclasses (defining concrete generic types) you have reflection information available at runtime of what where the generic parameters of each class. Then you could get the actual class of each property and retrieve the reflection data for that class.
This would also be possible if you have methods or fields that define those types and return/hold references to a propery. However, I doubt you have that information since you seem to get some list and don't know exactly on where and how the elements of that list were created.
I further assume the properties' class is Property only, not a subclass. Thus the only way is to provide the runtime information yourself, i.e. by passing a reference to the type class as a constructor parameter.
Okay I'm going to answer myself.
I'm now passing an instance of Class<?> to the Property-class.
Then I extract the basic name of the property and simply cut away "java.lang." which is possibly as in most cases, I'm doing this to primitive data types - resp. their autoboxing classes.
Further, I just instanciate a new instance of the wrapper by name and pass the to be wrapped property as a parameter to the constructor which applys for that.
Here some code for the interested ones among you:
String template = "..."; // some package definition
for (Property<?> crt : bag)
{
String className = template + crt.getClassName();
Class<? extends PropertyWrapper<?>> wrapperClass = null;
wrapperClass = (Class<? extends PropertyWrapper<?>>) Class.forName(className);
Constructor<? extends PropertyWrapper<?>> constructor = wrapperClass.getConstructor(new Class<?>[] {Property.class});
PropertyWrapper<?> wrapper = constructor.newInstance(crt);
// Further operations using the wrapper
}
for simplicity, I left out the error handling part.
Rather than instantiating the wrapper from the call site, why not have the Property know how to create its own wrapper? Something like:
public class Property<T extends Comparable<T>> {
PropertyWrapper<T> newWrapper();
}
That only half-helps, though. Your real problem is that in a loop like yours:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = crt.newWrapper();
}
The fact that the PropertyWrapper and the Property have the "same" type isn't very helpful, since that type is just the unbound wildcard.
I really hate to give one of those "what are you really trying to do" answers, but -- what are you really trying to do? Generally speaking, once you get to an unbound wildcard, all hope is lost (unless you're willing to do unsafe, uncheckable casts or bend over backwards with reflection checks). One way around this is to put as much of the action within the Property<T> as possible,before you put that property in the List<Property<?>>. My newWrapper() is an example of this: it puts the action of creating a PropertyWrapper<T> into the Property<T> itself. If you wanted to register a callback for when the property changed, that's also something you may be able to do at each place you instantiate a non-wildcard Property<Whatever>. For instance:
Property<UserLogin> property = new Property<UserLogin>();
SomeListener<UserLogin> listener = whatever();
property.addListener(listener);
wildcardedPropertiesList.add(property);
This particular example probably won't help, but hopefully it'll give you applicable ideas.

Categories