Reflections IllegalArgumentException causes

23,629

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);
Share:
23,629
Aditya
Author by

Aditya

Try to solve anything that strikes me as an interesting problem.. succeed sometimes, fail other times, keep trying!

Updated on April 23, 2020

Comments

  • Aditya
    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
      Perception about 11 years
      The 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
      Aditya about 11 years
      The 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
    Aditya about 11 years
    This 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
    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
    Aditya about 11 years
    There 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
    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
    Aditya about 11 years
    i 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
    Aditya about 11 years
    I have updated the question and added the code now. Hope it helps.
  • Jon Skeet
    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
    Aditya about 11 years
    I'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
    Aditya about 11 years
    my 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
    Aditya about 11 years
    This 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
    johnchen902 about 11 years
    @gap_j I had edited my answer to throw the exception in a zero argument method.
  • Aditya
    Aditya about 11 years
    the error is being recreated in your old case, with arguments. But with the modification (zero argument method), its not being recreated.
  • johnchen902
    johnchen902 about 11 years
    It recreated on my computer! Let me check what I forget to post. Uh... Probably you didn't roll ReflectionsInterface and doSomething back to your original example code version?
  • Aditya
    Aditya about 11 years
    I 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
    johnchen902 about 11 years
    @gap_j You need be modify both main and invokeMethod.
  • mki
    mki about 11 years
    gg 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
    GreenGiant over 9 years
    Can someone explain why IllegalArgumentException is being thrown for a call to a method that doesn't take any arguments?
  • Knox
    Knox over 5 years
    Is there a way to disable this optimization?