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.
Related
I've encountered the following code in a Java project, and I'm not sure what to make of it:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return ((Function<CustomEnum,String>) (someObject::toString)).andThen(r -> someObject::getSomethingWithEnumParameter);
}
I don't really understand how you can cast something to a Functional Interface. What does that even mean?
Isn't the resulting type of the return value going to be whatever value someObject.
Isn't Function<CustomEnum, String> defining an anonymous function that takes a type CustomEnum and returns a String?
I've read the java doc for Function<T,R>, and to be honest, this doesn't make much more sense than before I read the document.
This is what I believe is happening.
foo is returning an anonymous function that is applied to some CustomEnum to return a String
the anonymous function inside of foo (which is somehow cast onto someObject::toString, which I don't understand) is applied to the CustomEnum that will be passed from the initial call of foo(someObject).apply(customEnum).
The andThen will take the resulting String from the anonymous function inside of foo (which was cast somehow I still don't understand), and then return the value of someObject::getSomethingWithEnumParameter. Why isn't the return type just the type of someObject::getSomethingWithEnumParameter, which we'll say is a Map<R,T>, for sake of discussion.
If anyone could help me understand this flow, I would greatly appreciate it.
In an ideal world this would work:
public Function<CustomEnum,String> foo(SomeObject someObject) {
return (someObject::toString).andThen(...);
}
However Java needs an interface type in order to implicitly create an interface instance from the method reference., hence the explicit cast is required to cast to the Function interface type.
Once you have an instance of Function then you can call any method on it as per normal, in this case the andThen method which composes it with another function object to form a new function.
Breaking it down:
someObject::toString is a method reference with implied type Function<CustomEnum, String>. I.e. toString is a method on SomeObject which takes a parameter of type CustomEnum and returns a String.
r -> someObject::getSomethingWithEnumParameter has the wrong type though - it's a function which returns a function. If you get rid of the "r ->" part then it is valid, as long as someObject::getSomethingWithEnumParameter is a method on SomeObject that takes a String and returns a String. Alternatively the return type of foo would need to change to Function<CustomEnum, Function<String, String>>.
If you combine those two with andThen then you have a Function which takes a CustomEnum and returns a String, as pr the return type of foo.
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];
How can I create a list with a specified type argument?
For example:
LinkedList<Integer> list = createList(LinkedList.class, Integer.class);
I've tried creating a method for it, but the method doesn't include the type argument when creating the new instance.
public static <T, L extends List<T>> L createList(Class<L> listClazz, Class<T> valueClazz) throws Exception
{
return listClazz.getConstructor().newInstance();
//Instead of
// new L<T>();
//does
// new L();
}
I hope my question is clear enough, thank you for any help.
You can't do that. Generics have no business at runtime, so you can't create parameterized instance at runtime using reflection. At runtime, LinkedList<Intege> is just a LinkedList. The type information - Integer is erased at compile time through "type erasure". The point is, why would you like to do that?
//Instead of
// new L<T>();
//does
// new L();
The two "do" exactly the same thing. How do you know it "does" one and not the other? Type parameters are compile-time illusions for type-checking. They are not relevant in what the code "does". To create an instance of LinkedList<T>, you do not need to know what T is, because it doesn't really exist after type erasure.
I think the issue you are having has nothing to do with the code inside the function, but with the signature of the method. By the very fact that the method is declared as it is, and you are passing an expression of type Class<LinkedList> (the type of LinkedList.class) to it, L must be LinkedList, and since the method returns L, the compiler must consider its return to by type LinkedList. None of this has anything to do with the code inside the method.
If you want the method's return type to be considered as LinkedList<Integer>, then just pass in an expression of type Class<LinkedList<Integer>>. Simple, right? How do you get an expression of type Class<LinkedList<Integer>>? For one, you could do (Class<LinkedList<Integer>>)(Class<?>)LinkedList.class.
If that seems kind of bogus, it's because Class is fundamentally a runtime thing -- it allows runtime creation of an object from that class. Using it with Generics, a compile-time type-checking mechanism, is fundamentally flawed. There is just one class object in existence for any class, e.g. LinkedList. Is it LinkedList or LinkedList<Integer> or LinkedList<String>? Well, it could be all of these, in the sense the the newInstance() method could create any of them (there is no difference at runtime).
I am still experimenting with how Java handles generics. I stumbled upon the fact/issue/thing that if you have a generic interface like A<T>, you cannot really check afterwards if some object is actually implementing A<B> or A<C>.
I wondered if that could cause actual problems.
Now I have tried this code:
static interface A<T> { void foo(T obj); }
static class B implements A<B> {
public void foo(B obj) { obj.bar(); }
void bar() {}
}
static {
assert (new B() instanceof A<?>);
((A<?>) new B()).foo(new Object());
}
This gives me this error (for the foo-call):
The method foo(capture#1-of ?) in the type Main.A<capture#1-of ?> is not applicable for the arguments (Object)
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A<?> is foo(? obj) which I thought is the same as foo(Object obj).
The assert succeeds.
What I tried to figure out is at what point exactly does it cast the object when I call the foo function.
Also, how can I call foo from A<?>? This is the thing I actually need to be able to do. Or is that impossible with any other parameter than null?
A more real-world example where I actually wonder about this: I use the Comparable<T> interface a lot. That case is actually even more complicated; I might open another question about that if this here doesn't answer it.
I wonder why that is. Eclipse tells me that the signature of foo after the cast to A is foo(? obj) which I thought is the same as foo(Object obj).
Nope, absolutely not. Imagine A<T> is List<T> with foo(T) being add(T) and so A<?> is List<?>. Should you be able to do this?
List<String> strList = new ArrayList<String>();
List<?> wcList = strList;
wcList.add(Integer.valueOf(6)); //possible if add(?) is same as add(Object)
//...
String str = strList.get(0);
Of course not, since you'd get a ClassCastException in the final line.
What foo(?) really means is that the method applies to some unknown but specific type. You can't typically invoke these methods unless you pass null as the parameter, which is acceptable to assign to any reference type.
If you have "foo(? obj)" then the ? could be any type. If it is say String then you can't pass, say, an Integer to it. All you can pass is null.
Casting and use of instanceof should normally be avoided unless unavoidable (such as implementing equals), particularly with generics.
The compiler is correct because it does a compile-cast test on compile-time.
((A<?>) new B()).foo(new Object());
is errornous because the compiler expected
((A<?>) new B()).foo(A object)....
meaning that it wanted anything of type A or its children. Object is the parent of A and it doesn't match the compile-test Parameter type for compilation.
When you check if an instance of B is an instance of A<?> you just do the same thing as new B() instanceof A. You don't really check how T is set, it's just "something".
Later in the code with the cast, you tell that you'll use B as a A<?> so the variable will have the characteristic of a A but the generic type is still "something". This "something" exists and is probably a specified class but your don't care of the exact type.
That's why when you use the foo() method which take a T in parameter, you can't pass a "something" in parameter, because you don't know what it is, it could be an Object but it could be anything else.
Because of this the compiler tells you foo(capture#1-of ?) isn't applicable for the argument Object. The needed parameter is "something" but not necessarily an Object.
Then, when would you need this feature ?
For example if you work with a map, if you don't really care of the type of the key (if you only work with the values() method for example), you could do something like this :
Map<?, V> m
This way you won't be able to use features related to the key of the map (but you don't care about that), but you'll be able to use a map with any kind of key.
No, foo(? obj) is not actually the same as foo(Object obj). The difference is, when the parameter type is Object, it's explicitly stating that any type of object is legal. With a parameter type of ?, the method states that it does not know what type of object is legal... therefore nothing is legal except for null.
The reasoning for this becomes apparent when you consider a List rather than an arbitrary interface. Look at this method:
public void foo(List<?> list) {
list.add(...); // what can we add here?
}
The ? indicates that any type of List is acceptable... the List passed in could be a List<String>, a List<Integer> or a List<Map<Foo, Bar>>. There's no way of knowing. Note that this is only a problem with methods that consume generic parameters, such as add or your foo method. For methods that produce (return) an object of the generic type, it's fine to use such a method and assign the result as an Object. This, unlike the consumer method, cannot corrupt the internal state of the generic object.
Also notice that when you call ((A<?>) new B()).foo(new Object()), you're trying to do something illegal... if something (such as the Object) that is not a B were to be passed to B's foo method, it would explode at runtime. The compiler is correctly preventing you from doing this.
You may also want to check out my answer to another question here which explains some things about bounded wildcard types and such.
This is a simple explanation:
A<?> means A of unknown parametrized type. Given
A<?> ref = new B()
ref could point to any A: A<Object, A<String>, anything. So you can not call A.foo(new Object()) because in case of A<?> reference there is no way to know which parameter ref.foo() accepts. Actually the only thing valid is ref.foo(null).
Many have clarified that point about ? but noone has really answered the main question yet, so here it is:
It is possible to call A#foo like this:
((A) new B()).foo(new Object());
The cast then is done inside of foo.
I currently posses a List of Objects(Using Java 1.3), and let's say that I wanted to cast one of the Objects returned from list.get(i) to a type of which I only know the name of the Class as a String. Essentially, how do I
Object o = (classname)list.get(i); where className is a String variable of a className.
I thought that I could use ( Class.forName(className) )list.get(i), but I received a syntax error claiming that I forgot a semicolon.
Unfortunately, since I am using Java 1.3, I do not have access to the Class.cast(Object) method.
What is the name of the class used when casting to another type in Java 1.3? Is there some method that can give me the correct type I need with a String parameter of the class name?
what is the point of casting when all you do is assign the result to object?
All you would achieve is an exception if it did not implement the interface/extend or was the class or do nothing if it did.
For that a simple:
public static boolean IsInstance(object x, String className)
{
Class cls = Class.forName(className);
return cls.isInstance(x);
}
is sufficient (and cleaner)
If you were to the use reflection to get at the fields/methods of the class that's just fine
No, and you can't do this across most languages.
The reason is that the type to cast to has to be known at compile time, not at runtime (which is what you are trying to do).
If you think about it, it makes sense, because given that the variable could be any type name, how are you supposed to access the various members? You can't, not unless they are defined in a base type/interface that all instances implement, in which case you should just use that.
One scenario where the need for this arises is when enforcing type safety with a legacy system. For example, suppose you have a persistence system like Hibernate that provides a raw List of results from a "finder" method. Casting this raw List to a parameterized type will result in an unchecked warning, and if the List contains an object of the wrong type, a ClassCastException can be raised at an unspecified time in some distantly related code. It may be best to validate the contents of the list up front, using a mechanism like the OP suggests.
Here's the Java 1.3 version (without generics):
private static void checkType(Collection objs, String className)
throws ClassNotFoundException
{
Class clz = Class.forName(className);
Iterator i = objs.iterator();
while (i.hasNext()) {
Object obj = i.next();
if (!clz.isInstance(obj)) {
throw new ClassCastException();
}
}
}
In Java 5 and later, with generics, you can do something similar with the Class.cast() method to verify the contents of a collection, justifying the use of a SuppressWarnings annotation. In our review process, suppressing a warning without some "proof" that it is safe is filed as a bug.
I assume that you really wanted to write the following, instead of using Object on the left side. Since otherwise, it's really just about checking whether the object in the list is of the right type.
ClassName o = (classname)list.get(i);
Well, Java is statically typed. It's not possible that you give it a string and it gives you the corresponding static type, so that you can go without casting. Even with generics and Class<T>.cast, the cast destination type is not given by a string, but by the generic type-argument T, which is known at compile-time. You have to manually cast to the right type, or keep using the most common type (may be Object in your case).
If you do Class.forName(className), it gives you back an object of the type Class which contains information about the type at runtime, so that it allows you to do
Class.forName("my.stuff.MyClass").newInstance()
But the cast wants a type - not an object of some type. That is why the compiler told you there is something wrong with that code.
The static type of the reference returned by that is of Object. This is important: The dynamic type of an object that is referenced, and the static type of the reference that points to that object. The dynamic type of the object is what can be "controlled" by a string (by using Class.forName), but the static type of the reference that you have to do with at compile time, and that is (just to give an example) used to select functions that overload each other, can not be determined by a string.
The question was answered already, but I'd like to add that it seems a bit dubious that you should have a List in which you keep several different kinds of objects (in this case, any objects), yet you'd apparently like to invoke operations on them that are specific to each different type...
What's the point of this collection? Don't the instances you keep in it have anything in common - any common supertype that you could cast them into?