Reflections IllegalArgumentException causes
Solution 1
I had recreated the ClassCastException
by modifing your example code: Invoke invokeMethod
with a correct argument 10000 times, and then invoke it with wrong a wrong one.
The main
method in the Reflections
class
public static void main(String[] args) {
Reflections reflections = new Reflections();
ReflectionsInterface reflectionsProxy = reflections
.createProxy(ReflectionsInterface.class);
for (int i = 0; i < 10000; i++)
invokeMethod(reflectionsProxy, ReflectionsInterface.class,
"doSomething");
invokeMethod(new Object(), ReflectionsInterface.class, "doSomething");
}
The invokeMethod
method in the Reflections
class
public static void invokeMethod(Object obj, Class<?> clazz,
String methodName, Object... args) {
Method[] methods = clazz.getMethods();
try {
for (Method method : methods) {
if (method.getName().equals(methodName)) {
method.invoke(obj, args);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Stack Trace:
java.lang.IllegalArgumentException: java.lang.ClassCastException@603a3e21
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.twbbs.pccprogram.Reflections.invokeMethod(Reflections.java:33)
at org.twbbs.pccprogram.Reflections.main(Reflections.java:16)
My explanation of the ClassCastException
:
When you invoke invokeMethod
for the first time, JVM use a slower route, which is easier for programmers to debug (so it's slower!), so it will show a more friendly argument type mismatch
message when you passes a bad argument.
When you invoke invokeMethod
for a lot of times (16 times are enough in my tests), JVM generated a GeneratedMethodAccessor***
in runtime, which is faster, with less error checking. So it will show such an ugly java.lang.ClassCastException@603a3e21
message when you passes a bad argument.
Solution 2
Well this is the problem:
reflections.invokeMethod("doInt", 1L);
You're calling doInt
, but you're passing a long
value. So reflection is trying to cast a Long
to an Integer
, which is invalid.
I suspect you meant:
reflections.invokeMethod("doLong", 1L);
Aditya
Try to solve anything that strikes me as an interesting problem.. succeed sometimes, fail other times, keep trying!
Updated on April 23, 2020Comments
-
Aditya about 4 years
UPDATE - To make the question clearer.
What is the possible cause of getting a ClassCastException while calling a method via reflections?
I got the following stacktrace as a part of my application while trying to invoke a method via reflections.
java.lang.IllegalArgumentException: java.lang.ClassCastException@21fea1fv at sun.reflect.GeneratedMethodAccessor332.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com..... (remaining is my method stack trace)
I tried an example class and passed various arguments of different types to it, but i always get a this exception.
java.lang.IllegalArgumentException: argument type mismatch at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597)
UPDATE - Here is the sample code i wrote to try recreating the exception
Interface to create proxy class
package my.tests; public interface ReflectionsInterface { public abstract void doSomething(); }
This is the test class
package my.tests; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Reflections implements ReflectionsInterface { public static void main(String[] args) { Reflections reflections = new Reflections(); ReflectionsInterface reflectionsProxy = reflections.createProxy(ReflectionsInterface.class); invokeMethod(reflectionsProxy, "doSomething", null); } public <T> T createProxy(Class<T> entityInterface) { EntityInvocationHandler eih = new EntityInvocationHandler(this); T cast = entityInterface.cast(Proxy.newProxyInstance( entityInterface.getClassLoader(), new Class[]{entityInterface}, eih)); return cast; } public static void invokeMethod(Object obj, String methodName, Object... args) { Method[] methods = obj.getClass().getMethods(); try { for (Method method : methods) { if (method.getName().equals(methodName)) { method.invoke(obj, args); break; } } } catch (Exception e) { e.printStackTrace(); } } public void doSomething() { System.out.println("woo"); } private final static class EntityInvocationHandler implements InvocationHandler, ReflectionsInterface { private Reflections reflectionObj; public EntityInvocationHandler(Reflections reflectionObj) { super(); this.reflectionObj = reflectionObj; } @Override public void doSomething() { reflectionObj.doSomething(); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(this, args); return invoke; } } }
I am unable to understand the when i would get argument type mismatch and the ClassCastException would be caused. I am not able to re-create the exception and would like to know why it comes. Any working code that re-created it, or a source code reference throwing this exception in this case will be good
I have gone through the Method.class javadocs and source code, i am not able to figure out why this error comes.
-
Perception about 11 yearsThe recent edits you made to your code have eliminated the exception that was being thrown. Are you saying you are still getting errors even with this new SSCCE? If not, please revert back to the previous code that actually illustrates the issue you are having.
-
Aditya about 11 yearsThe error is coming from my application code, which is very elaborate and i cannot post here. This is my (failed) attempt to re-create the error or understand why it is coming..
-
-
Aditya about 11 yearsThis is not my application code. I am trying to re-create the classcast exception, so i purposely called a reflections.invokeMethod("doInt", 1L); The error that it throws here is argument type mismatch, not classcast exception
-
Jon Skeet about 11 years@gap_j: Ah, I see. That wasn't at all clear before. How close is this code to your actual application code though (in the reflection part)?
-
Aditya about 11 yearsThere are 2 differences between this and my application code. 1) the method being invoked in my application has no arguments. 2) It might be being invoked on a proxy class. I am trying to recreate using both these cases, still unsuccessful
-
Jon Skeet about 11 years@gap_j: If you're invoking a method with no argument, then I can't see that the sample code you provided is helpful at all - it clearly can't be an argument conversion issue if there are no arguments! It sounds much more likely that the proxy class difference is the important one. It's really important that a question gives as much context as possible: both of those points should have been in the question from the start.
-
Aditya about 11 yearsi did not post the whole code as i thought it'll be a little too much to post 2 classes and 1 interface here. I posted the a small part to give some context, i will update the question and add the full sample if it helps.
-
Aditya about 11 yearsI have updated the question and added the code now. Hope it helps.
-
Jon Skeet about 11 years@gap_j: Well you've updated the code, which is good - but it's still not clear what you are getting vs what you expect to get. If you're really just interested in the ClassCastException, then there's no point in having any methods with arguments. (And there's definitely no point in including the non-Javadoc comments.) Basically you need to trim the code to be short, complete, and still representative of just the situation you want us to understand.
-
Aditya about 11 yearsI'm interested only in the ClassCastException, but i thought it would be helpful enumerating the cases to save others the time. But i guess what you are saying is right, i've removed the code that might not be the cause. And thanks for the tips!
-
Aditya about 11 yearsmy original code post had 2 similar methods, and got the exception you are getting. But in my case the method throwimg exceptions has no arguments, i modified the example to reflect that.. I am interested only in the reasons the ClassCastException is thrown as i am able to recreate the other cases. (Refer to jon skeet's answer and the comments)
-
Aditya about 11 yearsThis is quite interesting, i will try this, but the method i'm trying to invoke has no arguments! Any idea why the exception might come in a zero argument method?
-
johnchen902 about 11 years@gap_j I had edited my answer to throw the exception in a zero argument method.
-
Aditya about 11 yearsthe error is being recreated in your old case, with arguments. But with the modification (zero argument method), its not being recreated.
-
johnchen902 about 11 yearsIt recreated on my computer! Let me check what I forget to post. Uh... Probably you didn't roll
ReflectionsInterface
anddoSomething
back to your original example code version? -
Aditya about 11 yearsI have it at the old version. and passing a new Object() to invokeMethod won't do anything as it won't find a method with a matching name. Are you sure this is the exact code you are using? Could you post the exact code here? Can you also specify which java version you are using.
-
johnchen902 about 11 years@gap_j You need be modify both
main
andinvokeMethod
. -
mki about 11 yearsgg John. I searched also a bit on this problem and I couldn't figure how to get this exception. Thx for the question and the answer. +1 for your answer ;)
-
GreenGiant over 9 yearsCan someone explain why IllegalArgumentException is being thrown for a call to a method that doesn't take any arguments?
-
Knox over 5 yearsIs there a way to disable this optimization?