9

更新 - 質問をより明確にする。Reflections IllegalArgumentExceptionの原因

リフレクションでメソッドを呼び出すときにClassCastExceptionを取得する可能性がある原因は何ですか?

リフレクションでメソッドを呼び出そうとしているときに、アプリケーションの一部として次のstacktraceを取得しました。

java.lang.IllegalArgumentException: [email protected] 
    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) 

私はサンプルクラスを試して、さまざまな型のさまざまな引数を渡しましたが、私はいつもこの例外を受け取ります。

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 - ここでのサンプルコードはある私は、これは

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

    } 
} 
テストクラスである

プロキシクラスを作成するには、例外

インターフェイスを再作成しようとする

package my.tests; 

public interface ReflectionsInterface { 
    public abstract void doSomething(); 
} 

を書きました

私は元に戻すことができません私が引数の型の不一致ClassCastExceptionが発生すると、私はerlします。 私は例外を再作成することができず、なぜそれが来るのか知りたいと思います。それを再作成した作業コードまたはこの例外をスローするソースコードのリファレンスは良いでしょう。

私はMethod.classのjavadocsとソースコードを使いましたが、なぜこれを理解できないのですか?エラーが発生します。

+0

コードに対して行った最近の編集により、スローされた例外が排除されました。あなたはこの新しいSSCCEであってもまだエラーが出ていると言っていますか?そうでない場合は、実際に問題が発生していることを示す前のコードに戻してください。 – Perception

+0

エラーは私のアプリケーションコードから来ています。これは非常に精巧で、私はここに投稿できません。これは私の(失敗した)エラーを再現するか、なぜ来るのか理解しようとしています。 –

答えて

13

例コードを変更してClassCastExceptionを再作成しました:invokeMethodを正しい引数で10000回呼び出して間違ったものを間違えて呼び出します。

Reflectionsクラスのmain方法

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

ReflectionsクラスのinvokeMethod方法

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

スタックトレース:ClassCastException

java.lang.IllegalArgumentException: [email protected] 
    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) 

私の説明:

初めてinvokeMethodを呼び出すと、JVMはプログラマーがデバッグするのが簡単な(ゆっくりです!)ため、悪い引数を渡したときにメッセージargument type mismatchが表示されやすくなります。

多くの時間(私のテストでは16回で十分です)invokeMethodを呼び出すと、JVMは実行時にGeneratedMethodAccessor***を生成しました。悪い引数を渡すと、そのような醜い[email protected]メッセージが表示されます。

+1

これはかなり面白いです、私はこれを試みますが、私が呼び出しようとしているメソッドは引数がありません!何故、例外がゼロ引数メソッドに来るのか? –

+0

@gap_j私はゼロ引数メソッドで例外を投げるために私の答えを編集していました。 – johnchen902

+0

あなたの古いケースでは、引数を使ってエラーが再現されています。しかし、変更(ゼロ引数メソッド)では、再作成されません。 –

1

まあ、これは問題です:

reflections.invokeMethod("doInt", 1L); 

あなたはdoIntを呼んでいるが、あなたがlong値を渡しています。反射はをIntegerにキャストしようとしていますが無効です。

私はあなたが意味を疑う:

reflections.invokeMethod("doLong", 1L); 
+0

これは私のアプリケーションコードではありません。私はclasscast例外を再作成しようとしているので、私は意図的にreflections.invokeMethod( "doInt"、1L)を呼び出しました。ここで投げられるエラーは、クラスキャストの例外ではなく、引数型の不一致です。 –

+0

@gap_j:ああ、わかります。これは、以前はすべて明らかではなかった。しかし、(反射部分の)実際のアプリケーションコードにこのコードがどれくらい近いのですか? –

+1

これと私のアプリケーションコードには2つの違いがあります。 1)私のアプリケーションで呼び出されるメソッドに引数がない。 2)プロキシクラスで呼び出されている可能性があります。私はこれらの両方の場合を使用して再作成しようとしていますが、まだ失敗しています –

0

Iビットは、このエラーを再現するようにコードを修正する必要があり:ここでは

java.lang.IllegalArgumentException: argument type mismatch 

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

がでメソッドを追加インターフェースでありますクラスReflectionsおよびEntityInvocationHandlerをコンパイルします。次にmain()にこのメソッドを追加します。実行してエラーランタイムを生成します。

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

私はClassCastExceptionを取得しようとしましたが、成功しませんでした。 より多くのオブジェクトがあり、無効な型がメソッドに渡されるため、おそらく元のコードで発生します。ログを追加し、ClassCastExceptionを分離するためにデバッグしようとします。

+1

私の元のコードポストは2つの同様のメソッドを持っていて、あなたが得ている例外があります。しかし、私の場合、メソッドthrowimg例外は引数がありません、私はそれを反映するために例を変更しました。*私は他のケースを再作成できるようにClassCastException *がスローされる理由にのみ興味があります。 (jon skeetの答えとコメントを参照してください) –

関連する問題