I have a field like List<? extends MyPojo> myPojos = new ArrayList<>();.
I want to -through reflection- get the fact that the upper bound of myPojos is of type MyPojo.
I can get the Field no problem, and then getGenericType, but that just returns a Type which has no methods on it. I can cast it to ParameterizedType, but getActualTypeArguments().
The toString() method on the ParameterizedType returns the expected value, there seems to be no way to access the information on the wildcard upper boud, and all the implementations of ParameterizedType seem to be in sun. packages.
So, can I -without parsing the toString() output- get the upperbound of the generic type without resorting to depending on sun.* classes? Or is this information lost due to erasure?
You do need to cast to ParameterizedType, and then cast the Type values from getActualTypeArguments() to WildcardType, which has a getUpperBounds() method.
So
assert MyPojo.class == ((WildcardType) ((ParameterizedType) listField.getGenericType()).getActualTypeArguments()[0]).getUpperBounds()[0];
Related
I have a method that gives me the type of an object:
public void decode(java.reflect.Type type){
//how to check if type extends MyAbstract.class?
}
And I need to make a cast if the type extends MyAbstract, an abstract class I created.
I tried with:
type instanceof MyAbstract
but doesn't seem to work...do you have any ideas?
First, a few clarifications:
A Type instance doesn't only represent classes. It can represents classes, parameterized types, as well as the type parameters themselves. It can even represent the wildcard type. If you look at the javadoc, you'll see these known subinterfaces:
GenericArrayType, ParameterizedType, TypeVariable<D>, WildcardType
instanceof checks that its left operand is an instance of the type specified as its right operand. Your
type instanceof MyAbstract
Doesn't quite make sense since it's checking whether the object referenced by the type variable is an instance of your custom MyAbstract type. Presumably, you haven't implemented a Type subclass that also extends your MyAbstract (but you might surprise me).
The type java.lang.Class also implements Type. If that's what you're really trying to check, then you'd first have to cast it to Class then use isAssignableFrom to check if MyAbstract is a superclass of that type.
if (type instanceof Class) {
Class<?> clazz = (Class<?>) type;
if (MyAbstract.class.isAssignableFrom(clazz)) {
System.out.println(true);
}
}
If your Type is not a Class, you have to reason about what it is. If it's a ParameterizedType, you can probably use its getRawType method to get the raw type (but you'd have to repeat the check for Class). If it's a TypeVariable, you can checks its bounds with getBounds().
As a preface to my question, please note that I know what type erasure is. I feel the need to state this so useful answers don't get buried in basic explanations.
I would like to obtain the class object for class List. For a non-generic type, I would use a class literal like String.class, but for List, even though I can obtain the correct behavior, I still get warnings that I am doing it wrong.
From my understanding, the class object for List would be of type Class<List>, but even writing down that type,
Class<List> c = null;
gives a warning: "Raw use of parameterized class 'List'". Due to type erasure, the class object cannot have knowledge about list elements, so my next guess would be
Class<List<?>> c = null;
which as a type gets accepted. Next I have to obtain the class object, but every way of trying to write down a class literal fails:
Class<List<?>> l = List.class;
gives a hard type error, while
Class<List<?>> l = List<?>.class;
says "Cannot select from parameterized type".
Class<List<?>> l = (Class<List>)List.class;
Fails with the same hard type error as without the cast (expected since the cast is redundant), and
Class<List<?>> l = (Class<List<?>>)List.class;
says "inconvertible types".
Next, I tried the following invalid code snippet to learn something from the compiler error:
List<?> l = new ArrayList<>();
int x = l.getClass();
Now the compiler gives a type error for Class<? extends java.util.List> -- ignoring the "extends" part for a moment, which is obvious since getClass() could return a subclass, this tells me that .getClass() only wants to talk about the raw List type, not List<?> or similar. In a way, that seems correct to me, since the class object represents any List instance, not "lists whose type is unknown". However, I'm back to square one now because just writing down the raw type gives a warning, so I'm obviously not expected to do that (I understand that raw types can be used to deal with legacy code, but I'm not doing that here).
I understand that I could throw away all static type information about the class object like this:
Class<?> c = List.class;
But this is often not feasible, and indeed I'm trying to solve a larger problem where I need that type information.
While I know that I can easily disable warnings or use similar dirty tricks, I would like to know what the correct way is to obtain the class object for List.
There is no way you can win this war.
There is no such thing as an instance of Class<List<?>>, or whatever. That's a valid type, but there is no concrete value that you can assign to that (other than null), because List.class and new ArrayList<>().getClass() have type Class<List> and Class<? extends List> respectively.
Class instances are inherently raw-typed, because of type erasure.
You can do unchecked casts:
Class<List<?>> clazz = (Class<List<?>>) (Class<?>) List.class;
but that will also generate warnings; and since you can do other unsafe casts, like:
Class<List<?>> clazz1 = (Class<List<?>>) (Class<?>) ArrayList.class;
you might end up in an odd situation where two instances of Class<List<?>> are unequal, or for example that sometimes a Class<List<?>> can be instantiated (using clazz.newInstance()), and other times not.
Now, if you need some sort of generic type token, you can use something like what Guice does:
TypeLiteral<ArrayList<?>> typeLiteral =
new TypeLiteral<ArrayList<?>>() {};
It is possible to obtain the ArrayList<?> from that at runtime, because of the way the superclass is captured (note the {} - this is an anonymous subclass of TypeLiteral). You can implement this yourself quite easily if you don't want to take a dependency on Guice (or other libraries which offer similar constructs), using typeLiteral.getClass().getGenericSuperclass().
But whether that is an approach you can take depends on your undisclosed problem. The key takeaway is that generics and reflection just don't play nicely together.
I'm trying to access a HashMap<String, Number> via reflection:
Serializable obj; //here goes the HashMap
String name;
...
return (double)obj.getClass().getDeclaredMethod("get", Object.class).invoke(obj, name);
but so far all I got is a casting error caused by the line above:
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Double
Indeed, the map value that was accessed by the key name was Integer.So I've changed the line to:
return obj.getClass().getDeclaredMethod("get", Number.class).invoke(obj, name).doubleValue();
but that didn't work out either. I even got doubleValue() underlined as "undefined for the type Object" (but why Object if I have Number.class?).
I'm not sure what casting rules I'm breaking. Can someone, please, help me if my map entries have various number values (Integer, Float, Double) but I need the method to return a double value (primitive).
PS
It's not really a duplicate. My question is more general. But thank you for your input. I forgot that invoke always returns Object.
The working code is:
return ((Number)obj.getClass().getDeclaredMethod("get", Object.class).invoke(obj, name)).doubleValue();
You have the wrong assumption that there was a relationship between the Class object you pass to getDeclaredMethod and the return type of Method.invoke.
The Class objects you pass to getMethod or getDeclaredMethod describe the parameter types of the method, not the return type.
Further, while you may pass arguments of a subtype of the declared parameter type, you have to specify exactly the declared parameter type.
The parameter type of Map.get is Object, invariably, so you have to specify Object.class, regardless of which actual key you will pass to invoke.
Further, due to type erasure, the reflective return type will always be Object, regardless of the actual Map’s parametrization.
Not that it matters, Method.invoke’s declared return type is always Object, as different Method instances may represent different methods.
So when you have a HashMap<String, Number>, you can rely on the returned objects to be Number instances, but not necessarily Double instances. As you experienced, there could be Integer instances. So what you have to do, is to type-cast to Number, followed by invoking doubleValue():
return ((Number)obj.getClass().getDeclaredMethod("get", Object.class)
.invoke(obj, name)).doubleValue();
That said, if you know that the object implements the Map interface, there is no reason to use Reflection at all:
return ((Number)((Map<?,?>)obj).get(name)).doubleValue();
does the job much more efficient.
I have read Get type of a generic parameter in Java with reflection post and it made me wonder how that would be possible. I used the solution that someone posted and using the code
List<Integer> l = new ArrayList<>();
Class actualTypeArguments = (Class) ((ParameterizedType) l.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
This, however does not work for me, resulting in
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
If I remove the class cast, the type of the actual argument is E, which is the type definition from List interface.
My question is, therefore, am I doing something wrong here? This behaviour is something I would have expected anyway, since the types are supposed to be erased during compile time, correct?
The code you use only works in some very specific cases, where the actual type parameter is known (and stored) at compile time.
For example if you did this:
class IntegerList extends ArrayList<Integer> {}
List<Integer> l = new IntegerList();
In this case the code you showed would actually return Integer.class, because Integer is "baked into" the IntegerList.
Some libraries (ab)use this trick via the use of type tokens. See for example the GSON class TypeToken:
Represents a generic type T. You can use this class to get the generic type for a class. > For example, to get the generic type for Collection<Foo>, you can use:
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>(){}.getType()
This works because the anonymous class created in here has compiled-in the information that its type parameter is Collection<Foo>.
Note that this would not work (even if the TypeToken class wouldn't prevent it by making its constructor protected):
Type typeOfCollectionOfFoo = new TypeToken<Collection<Foo>>().getType()
The javadoc will tell you what you are doing.
Class#getGenericSuperclass() states
Returns the Type representing the direct superclass of the entity
(class, interface, primitive type or void) represented by this Class.
If the superclass is a parameterized type, the Type object returned
must accurately reflect the actual type parameters used in the source
code. [...]
The direct superclass of ArrayList is AbstractList. The declaration is as such in the source code
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
So if you print out the Type object returned by it, you will see
java.util.AbstractList<E>
and therefore ParameterizedType#getActualTypeArguments() which states
Returns an array of Type objects representing the actual type
arguments to this type.
will return the Type
E
since E is the actual type argument used in the ArrayList class definition.
The method you described does ONLY work, when the Generic Type is Set due to inheritance, because then its known during compile time:
public class SomeClass<T>{
}
public class SpecificClass extends SomeClass<String>{
}
For this example, you can use the method and you'll get back "String.class".
If you are creating instances on the fly it won't work:
SomeClass s = new SomeClass<String>(); //wont work here.
Some common work around is, to pass the actual class as a parameter for later reference:
public class SomeClass<T>{
Class<T> clazz
public SomeClass(Class<T> clazz){
this.clazz = clazz;
}
public Clazz<T> getGenericClass(){
return this.clazz;
}
}
usage:
SomeClass<String> someClass= new SomeClass<String>(String.class);
System.out.println(someClass.getGenericClass()) //String.class
Actually you don't even need the Generic type for such an scenario, because Java would do the same thing, as if you would handle the "T" as Object. Only advantage is, that you can define getter and Setter of T and don't need to typecast Objects all the time. (Because Java is doing that for you)
(It's called Type Erasure)
I don't understand what is the use of unbound wildcards generics. Bound wildcards generics with upper boundary <? extends Animal> makes perfect sense, because using polymorphism I can work with that type or collection. But what is the point of having generics that can be of any type? Doesn't it defeat the purpose of generics? Compiler doesn't find any conflict and after type erasure it would be like no generics was used.
An unbound type can be useful when your method doesn't really care about the actual type.
A primitive example would be this:
public void printStuff(Iterable<?> stuff) {
for (Object item : stuff) {
System.out.println(item);
}
}
Since PrintStream.println() can handle all reference types (by calling toString()), we don't care what the actual content of that Iterable is.
And the caller can pass in a List<Number> or a Set<String> or a Collection<? extends MySpecificObject<SomeType>>.
Also note that not using generics (which is called using a raw type) at all has a quite different effect: it makes the compiler handle the entire object as if generics don't exist at all. In other words: not just the type parameter of the class is ignored, but also all generic type parameters on methods.
Another important distinctions is that you can't add any (non-null) value to a Collection<?>, but can add all objects to the raw type Collection:
This won't compile, because the type parameter of c is an unknown type (= the wildcard ?), so we can't provide a value that is guaranteed to be assignable to that (except for null, which is assignable to all reference types).
Collection<?> c = new ArrayList<String>();
c.add("foo"); // compilation error
If you leave the type parameter out (i.e. use a raw type), then you can add anything to the collection:
Collection c = new ArrayList<String>();
c.add("foo");
c.add(new Integer(300));
c.add(new Object());
Note that the compiler will warn you not to use a raw type, specifically for this reason: it removes any type checks related to generics.
When you need to perform an instanceof check.
You can't parameterize like this:
Object value;
if (value instanceof List<String>) {
// ...
}
So you do:
Object value;
if (value instanceof List<?>) {
// ...
}
While using raw types means that you don't know about generics (because you're lazy or code was written ages ago), using <?> means that you know about generics and explicitly emphasize that your code can work with any kind of objects.
There are (rare) perfectly correct use cases for unbound wildcards. The SDK contains some of them.
One example is a method that does a definite action on a list of any kind and does not return anything as rotate in Collections:
static void rotate(List<?> list, int distance)
Another example is when you want to list the possible constructors for a class, the method is :
Constructor<?>[] getConstructors()
Here it in not even possible to use a generic, because by definition the array will contain different constructor each with its own actual class. By contrast, the API does use a generic signature for getting one single constructor : Constructor<T> getConstructor(Class<?>... parameterTypes).
The conclusion is that even if it is mainly used for compatibility with older code, there are still places where unbound wildcard generics are the correct way.
Allow me to rephrase the question:
"What is the difference between List<Object> and List<?> ?"
The answer to that is that List<?> is more restrictive. It tells us that we have a bunch of object of some type, but that type is not necessarily Object.
Since we don't know what that type is, we cannot add to the list at all - anything we add may be of wrong type. In fact, we cannot pass any argument of ? type to any method, not just add().
On the plus side, when we specify that a method takes List<?>, it can take List<String> or List<Integer> or any other List<>. List<Object> can only take List<Object>.
Using unbounded wildcards only makes sense, AFAIK, when wrapping old code that is not using generics, basically Collections.
If you look at what you can do with such a generic it's basically nothing.
If you have a collection you can't add anything, if you try to read something out you will always get an Objectand so on.
This in turns helps guaranteeing that you will handle the data in a type safe way, whereas using the raw type would have caused the compiler to ignore any mess you'd make.
Which methods and fields are accessible/inaccessible through a reference variable of a wildcard parameterized type? from Angelika Langers Java Generics FAQ might be of interest.
List<Object> is a List that may contain any Object, e.g. l[0] may be an Integer, l[1] may be a String, etc.
List<?> may be a List<Integer> or List<String>, etc. If it is a List<Integer>, it stores only Integers, if it is List<String>, it stores only Strings.