2011-06-24 12 views
1

私は次のインターフェースを生成するいくつかのJavaコードを使用しています。このコードは変更不可能です。Java動的アダプター

interface A1 { 
    public void run(); 
} 

interface A2 { 
    public void run(); 
} 

... 

interface A24 { 
    public void run(); 
} 

次のコードでクラスキャストエラーが発生しました。私はどのように私のインターフェイスにアダプタを動的に構築するのですか?

interface ARunnable { 
    public void run(); 
} 

public void someMethod() { 
    // getARunnables() returns a list of A1, A2, ... A24 
    List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

    for (ARunnable a : runnables) { 
     a.run(); 
    } 
} 
+0

インターフェイスとクラスが異なるクラスローダーに存在するため、ClassCastExceptionが発生しています。 – mschonaker

+0

これらの各インタフェースA1->共有の共通インタフェースはありますか?何かのように: インターフェイスA1はARunnableを拡張します。{} –

+0

アミール:いいえ、彼らは –

答えて

1

インタフェースがjava.lang.Runnableのを拡張するように変更することはできませんので、オプションはあなたのA1、A2へのRunnableのインスタンスそのデリゲートを構築するjava.lang.reflect.Proxyのを使用することです。 ..インタフェース。

これは簡単なことではありませんが、この例をjava.lang.reflect.Proxyで見てみましょう。このサンプルは、単にメソッド名に基づいてデリゲートオブジェクトに委譲します。

public class ProxyTest 
{ 
    public static void main(String... args) 
    { 
     List<?> instances = Arrays.asList(new A1()); 
     List<ARunnable> runnableInstances = new ArrayList<ARunnable>(instances.size()); 
     for (Object instance : instances) 
     { 
      ARunnable runnableInstance = (ARunnable)Proxy.newProxyInstance(
              ARunnable.class.getClassLoader(), 
              new Class<?>[] {ARunnable.class}, 
              new RunnableWrapper(instance)); 
      runnableInstances.add(runnableInstance); 
     } 

     //Now we have a list of ARunnables! 
     //Use them for something 
     for (ARunnable runnableInstance : runnableInstances) 
     { 
      runnableInstance.run(); 
     } 
    } 

    private static class RunnableWrapper implements InvocationHandler 
    { 
     private final Object instance; 

     public RunnableWrapper(Object instance) 
     { 
      this.instance = instance; 
     } 

     @Override 
     public Object invoke(Object proxy, Method method, Object[] args) 
       throws Throwable 
     { 
      //Ensure that your methods match exactly or you'll get NoSuchMethodExceptions here 
      Method delegateMethod = instance.getClass().getMethod(method.getName(), method.getParameterTypes()); 
      return(delegateMethod.invoke(instance, args)); 
     } 
    } 

    public static class A1 
    { 
     public void run() 
     { 
      System.out.println("Something"); 
     } 
    } 

    public static interface ARunnable 
    { 
     public void run(); 
    } 
} 

また、私はあなたが

List<ARunnable> runnables = (List<ARunnable>)getARunnables(); 

ラインあなたが無視するべきではないと型の安全性警告を修正することをお勧めします。そのオブジェクトのリストには実際にはARunnablesが含まれていないため、ClassCastExceptionが存在します。

import java.lang.reflect.InvocationHandler; 
    import java.lang.reflect.Method; 
    import java.lang.reflect.Proxy; 

    public class Main { 

     interface Interface { 
     public void run(); 
     } 

     static class Hello /* does't implement Interface */{ 

     public void run() { 
      System.out.println("Hello, world!!"); 
     } 
     } 

     static <T> T dirtyCast(Class<T> intrface, final Object target) { 

     return intrface.cast(Proxy.newProxyInstance(
      intrface.getClassLoader(), 
      new Class<?>[] { intrface }, new InvocationHandler() { 

      @Override 
      public Object invoke(Object proxy, Method method, 
      Object[] args) throws Throwable { 

       Method targetMethod = target.getClass().getMethod(
       method.getName(), method.getParameterTypes()); 

       return targetMethod.invoke(target, args); 
      } 

     })); 
     } 

     public static void main(String[] args) { 

     Interface proxy = dirtyCast(Interface.class, new Hello()); 

     proxy.run(); 

     } 
    } 

あなたは引数を渡すか、値を返すか、例外をスローする場合に実現可能なように、このソリューションを考慮しないでください。

+0

ありがとう!チャームのように働いた –

0

は、このサンプルコード(単純化のためのループを持っていない)考えてみましょう。問題は、共有オブジェクト(引数および戻り値と例外として)が同じ(共通の)クラスローダーに存在する必要があることです。これはまた、通常のJavaのlangの型と例外が正常になることを意味します。

また、セキュリティ上の考慮事項に注意する必要があります。クラスローダーには、異なる(互換性のない)セキュリティ制約があります。

すぐに問題が発生した場合は、transloaderのようなプロジェクトを試してみます。

楽しんでください。

関連する問題