Question

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.

Was it helpful?

Solution

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.

OTHER TIPS

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);

I have a bit modify your code to reproduce this error :

java.lang.IllegalArgumentException: argument type mismatch

Here is the interface

public interface ReflectionsInterface
{
  public abstract void doSomething1(Integer i);
  public abstract void doSomething2(String s);
}

Add the method in class Reflections and EntityInvocationHandler in order to compile. Then add this method in your main(). Execute and I produce the error runtime.

invokeMethod(reflectionsProxy, "doSomething1", "1");

I have tried to get un ClassCastException but I didn't succeed. It occurs probably in your original code because there are more objects and an invalid type is passed to the method. Add logs and try to debug to isolated the ClassCastException.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top