2016-11-23 2 views
4

私は、ランタイム、e。で、このクラスのコピーを入手したいクラス実行時にJavaクラスのコピーを作成するにはどうすればよいですか?

class Foo { 
    int increment(int x) { 
     return x + 1; 
    } 
} 

を持っています。 g。

class Foo$Copy1 { 
    int increment(int x) { 
     return x + 1; 
    } 
} 

同じメソッドではありますが、異なる名前です。

Proxy

はすべて自分の体を持つメソッドをを委任 を助けるように見えるが、ないコピー

+2

なぜそれをしたいですか?メソッドはインスタンス化されません。あなたはオブジェクトではなくクラスについて話していますか? –

+3

明らかな問題は、なぜこれをしたいのですか?標準のクラスローダを通してロードされたクラスを元のクラスファイルに変換することはできません。あなたができることは、独自のクラスローダを作成して 'defineClass()'の呼び出しを傍受することです。 – biziclop

+0

@biziclop私はコピーされたメソッド内の各メソッド呼び出しのプロファイルをきれいな単相性に保ちたい。 – leventov

答えて

8

あなたはこのためにByte Buddyを使用することができます。例えば、このアプローチはFoo内のクラスのいずれかの用途を再定義することを

Class<?> type = new ByteBuddy() 
    .redefine(Foo.class) 
    .name("Foo$Copy1") 
    .make() 
    .load(Foo.class.getClassLoader()) 
    .getLoaded(); 

Method method = type.getDeclaredMethod("increment", int.class); 
int result = (Integer) method.invoke(type.newInstance(), 1); 

は注意、メソッドがFooを返した場合は、Foo$Copy1を返します。すべてのコード参照で同じです。

+0

ありがとうございます。これはプライベートClassLoaderの 'defineClass()'メソッドを使用するのでしょうか、別の方法ですか? – leventov

+0

第2引数として 'ClassLoadingStrategy'を選択することができます。デフォルトでは、ブートストラップクラスローダが与えられていない限り、 'Foo'のクラスローダへの注入が使用されます。 'ClassLoadingStrategy.Default.WRAPPER'では、スローアウェイクラスローダーを作成することもできます。 –

0

バイトコードへの通常のアクセス権があれば、Unsafeを使用すれば十分でしょう。

Foo.class.getClassLoader().getResourceAsStream()のようなものは、クラスのバイトコードを与えることができます。

sun.misc.Unsafe.defineClass(String name, byte[] code, int off, int len, ClassLoader classLoader, ProtectionDomain protectionDomain)を使用して、Fooと同じクラスローダーと保護ドメインにクラスを定義しますが、名前は異なります。

詳細はわかりますが、サードパーティのライブラリがなくても最も簡単なアプローチかもしれません。

+0

おそらく、ByteBuddyアプローチは、より柔軟で、後で維持する方が簡単です。 –

+2

しかし、クラスファイル内のクラス名と自己参照を再定義する必要があります。単に 'Foo'という名前のクラスファイルを使うだけではうまくいきません。 –

2

@leventovこの場合はどうすればよいですか? https://gist.github.com/serkan-ozal/8737583841b4b12e3a42d39d4af051ae

+0

おそらくこれはJavassistを既に使用している人にとっては正しい解決策です。私はJavassistとByte Buddyの間に優先順位がありませんでした。 – leventov

+0

@leventovに加えて、JDKのBCELを使用することもできます(JDKから来ていますが、public APIではなく、com.sun.org.apache.bcel.internal Javassistに依存することなく)。 – sozal

+0

のようなものです。 文字列copyClassName = classToBeCopied.getName()+ "$ Copy"; ClassGen classGen = new ClassGen(Repository.lookupClass(classToBeCopied)); classGen.setClassName(copyClassName); byte [] bytecode = classGen.getJavaClass()。getBytes(); 返品UNSAFE。defineClass( copyClassName、 バイトコード、 0、 bytecode.length、 classToBeCopied.getClassLoader()、 classToBeCopied.getProtectionDomain())。 ' – sozal

関連する問題