2013-05-08 10 views
8

要約: 1.私は、動的プロキシを作成する最終的なクラスをいくつか持っています。どうしたらいいですか? 2. MethodHandleをMethodに変換できますか?finalクラスの動的プロキシはどのように作成できますか?

詳細 まず、MethodHandleをメソッドに変換するAPIはありますか? java.lang.invoke.MethodHandlesのようなもの

public MethodHandle unreflect(Method m) throws IllegalAccessException; 

しかし、逆の方法ですか?

私は動的なjava.lang.reflect.Methodを作成したいとしましょう。

public final 
    class Method extends AccessibleObject implements GenericDeclaration, 
               Member ; 

私はJDKのダイナミックプロキシを使用したいと思うので、私はいくつかのインターフェース(例えばMember)を使わなければなりません。しかし、2つの主要なdrawabacks。それらは広く使用されつつ、第1、例えば

public Class<?>[] getParameterTypes(); 

など

public Class<?> getReturnType(); 

限り方法は、任意のインターフェイスの一部ではありません。

第2の欠点は、ドロップイン置換を提供できないことである。つまり、動的プロキシをjava.lang.reflect.Methodが必要なコードに渡すことはできません。

もう1つの方法は、CGLIBまたはJavaassistを使用することです。 AFAIK、CGLIBは最終クラスを代理することはできません、彼ですか? Javaassistプロキシファイナルクラスを使用できますか?クラスから最終的な識別子を「削除」するにはどうすればよいですか? AFAIL、Javvassistは何とかそれを行うことができます...

答えて

0

申し訳ありませんが、何をしたいことはできません。

これらのライブラリは、動的クラスのサブクラスを生成するので、あなたは具体的なクラスのプロキシを作成するためにCGLIBやJavassistのを使用することができますプロキシをしようとしています。 finalクラスはサブクラス化できないため、このようにプロキシを作成することはできません。

PowerMockは、クラスとメソッドをプロキシにすることができますが、特別なClassLoaderでテストを実行するので、Javassistを使用して、プロキシをロードするときのクラスのバイトコードを変更します。 (一般的に、特定の模擬単体テストを実行する以外には結果が得られないクラスの「ゾンビ」バージョンが修正されているため、この種のものを実際に使用することは望ましくありません)。

PowerMockのアプローチはここでは機能しませんが、ブートストラップクラスパスにあるjava.lang.reflect.Methodをプロキシしたいので、PowerMock/Javassistタイプのツールの前にロードされ、プロキシー対応ではありません。

9

必要なプロキシの種類によって異なります。基本的に3つの方法があります。そのうちの2つは実動コードで実行可能です。 @provenkelyで述べたように、cglibやjavassistの問題は最終的なクラスでは不可能なサブクラスを動的に作成することです。

  • バイトコード検証を無効にすることで、これを回避できます。 Javaランタイムは、悪質なバイトコードがロードされないようにするために、バイトコードを検証します。例えば、アプレットなど、ネットワークやインターネットを介してクラスを受信する場合には、これは重要です。このようにして、バイトコードベリファイアがあなたを止めることはないので、最終クラスのサブクラスを作成することができます。仮に、信頼できるコードのみを実行する場合は、この確認を無効にすることができます。これは、次のコマンドを実行することで実行できます。

    java -Xverify:none ApplicationName 
    

    これは、私があなたにおすすめする解決策です。私は生産コードのためにこのaproachを使用しませんが、実装するのが最も簡単な解決策です。

  • final修飾子は、クラスがロードされる前または後に、ロードされたクラスから削除します。これは、Java agentを使用して達成できます。 Javaエージェントは、アプリケーションの起動時に、コマンドラインまたは実行時にAttach APIを介してインストールできます。 ASMのようなバイトコードツールを使用すると、元のバイト配列を解析して、すべての関心クラスから最終修飾子を削除できます。既にロードされたクラスを再定義することもできます。 final修飾子を削除しても、古いクラスのバージョンと競合することはなく、そのような再定義は常に可能です。

  • final修飾子を削除して説明したのと同じ操作を行いますが、ロードされたクラスを再定義して、元のクラス内のすべてのインストゥルメンテーションロジックを実際に含むようにします。このaporachはほとんどのcertanly最大の努力を必要としますが、これはあなたのinstrumentationを他のすべてのコードに変換するでしょう。これは、すべてのソリューションの中で最もクリーンなソリューションです。

+0

最後のオプションを詳しく説明できますか? – piotrek

+0

インストルメンテーションAPIを使用してクラスを再定義することができます。たとえば、クラスはメソッドfooを定義します。メソッドバーの名前を変更し、再定義した新しいメソッドfooから呼び出すことができます –

関連する問題