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.
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.