2009-10-20 7 views
6

だから、私はこの答えはおそらく「それは難しい」さを実現、しかし:Java:実行時に型の新しい実装を作成しますか?

私は奇妙なアイデアを持っている、そしてそれはのような方法で作成するJavaで可能かどう思っていた:

<T> T wrapInterface (Class<T> interfaceClass, T wrappedObject) { 
    if (mClass.isInterface()) { 
    //create a new implementation of interfaceClass that, in each method, 
    //does some action before delegating to wrappedObject 
    return thatImplementation; 
    } 
} 

基本的には、私のインタフェースFooがメソッドfoo()を定義していたら、このメソッドはこのように見える新しいクラスを作成し、そのクラスのインスタンスをコンストラクタパラメータとしてwrappedObjectで作成して返します。 :

public class GeneratedClass implements Foo { 
    private Foo wrapped; 
    public GeneratedClass (Foo wrapped) { 
    this.wrapped = wrapped; 
    } 
    @Override 
    public void foo() { 
    System.out.println("Calling Foo.foo() on wrapped object " + 
         wrapped.toString()); 
    wrapped.foo(); 
    } 
} 

アプリケーション私は、呼び出しをログに記録するよりも複雑であると考えていますが、ロギングだけで十分です。私は多くのインターフェイスタイプでこれをやりたいので、GeneratedClassesを手で書くのではないのです。

標準的なJDKライブラリだけで可能な場合は、余分な言語機能(AspectJやそのような行に沿ったもの)を必要としないソリューションのボーナスポイントとダブルボーナスポイント。

(私は正確に、コンパイル可能な答えを必要としません;。私はこれをやらせるだろうツール/ライブラリ/などの権利セットにだけポインタ)

ありがとう!

+0

反射は、余分な言語的特徴です。 –

+0

[動的プロキシクラス](http://docs.oracle.com/javase/7/docs/technotes/guides/reflection/proxy.html)を調べるとよいでしょう。 –

答えて

3

ここでは非常に単純な実装です(あなたがしたいことのためには十分ではないかもしれませんが、いくつかの調整が必要です)。主なことはクラスローダーの問題です。 )私はテストの目的でコードを使用しているため、正確にはプロダクション品質のものではありません。

@SuppressWarnings("unchecked") 
    public static <T> T generateProxy(Object realObject, Class<?>... interfaces) { 
     return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject)); 
    } 


    private static class SimpleInvocationHandler implements InvocationHandler { 
     private Object invokee; 

     public SimpleInvocationHandler(Object invokee) { 
      this.invokee = invokee; 
     } 

     public Object invoke(Object proxy, Method method, Object[] args) 
       throws Throwable { 
      method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes()); 
      if (!method.isAccessible()) { 
       method.setAccessible(true); 
      } 
      try { 
       return method.invoke(invokee, args); 
      } catch (InvocationTargetException e) { 
       throw e.getTargetException(); 
      } 
     } 
    } 
+0

答え(とサンプルコード)ありがとう! – Sbodd

1

必要なものはASMです。

ASM-ガイド.pdfから:
2.2.3生成クラス
クラスを生成するための唯一の必須成分はClassWriter成分です。 例を挙げてこれを説明しましょう。次のインタフェースを考える:

package pkg; 
public interface Comparable extends Mesurable { 
    int LESS = -1; 
    int EQUAL = 0; 
    int GREATER = 1; 
    int compareTo(Object o); 
} 

それは、6つの方法で生成することができるClassVisitorの呼び出し:( `java.lang.Class`を含む)

ClassWriter cw = new ClassWriter(0); 
cw.visit(V1_5, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE, 
    "pkg/Comparable", null, "java/lang/Object", 
    new String[] { "pkg/Mesurable" }); 
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "LESS", "I", 
    null, new Integer(-1)).visitEnd(); 
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "EQUAL", "I", 
    null, new Integer(0)).visitEnd(); 
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "GREATER", "I", 
    null, new Integer(1)).visitEnd(); 
cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "compareTo", 
    "(Ljava/lang/Object;)I", null, null).visitEnd(); 
cw.visitEnd(); 
byte[] b = cw.toByteArray(); 
関連する問題