Reflections IllegalArgumentException causes
Asked Answered
C

3

11

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.

Cuttler answered 16/4, 2013 at 16:46 Comment(2)
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.Septuplicate
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..Cuttler
B
16

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.

Bruns answered 22/4, 2013 at 13:32 Comment(9)
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?Cuttler
@gap_j I had edited my answer to throw the exception in a zero argument method.Bruns
the error is being recreated in your old case, with arguments. But with the modification (zero argument method), its not being recreated.Cuttler
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?Bruns
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.Cuttler
@gap_j You need be modify both main and invokeMethod.Bruns
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 ;)Poi
Can someone explain why IllegalArgumentException is being thrown for a call to a method that doesn't take any arguments?Veii
Is there a way to disable this optimization?Jed
L
1

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);
Log answered 16/4, 2013 at 16:49 Comment(8)
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 exceptionCuttler
@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)?Log
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 unsuccessfulCuttler
@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.Log
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.Cuttler
I have updated the question and added the code now. Hope it helps.Cuttler
@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.Log
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!Cuttler
P
0

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.

Poi answered 20/4, 2013 at 10:56 Comment(1)
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)Cuttler

© 2022 - 2024 — McMap. All rights reserved.