2013-12-17 10 views
5

私は昨晩Java8 Lambdaで遊んでいましたが、実行時にラムダ式を取得できるかどうかは疑問でした。要するに、ラムダ式は実行時に(静的な)メソッドに変換され、InvokeDynamicsを使って呼び出されます。 filterがパラメータとしてPredicate<T>を取ってカスタムメソッドになり実行時にラムダ式を取得することは可能ですか?

people.filter(person -> person.getAge() >= minAge); 

はのは、このように例を見てみましょう。 このfilterメソッドの中で、この場合、ラムダ式(person -> person.getAge() >= minAge)と同様の(または同一の)形式で引数を取得するにはどうすればよいですか?

引数のクラスの生成されたバイトコードをASM5_BETAを使用して読み取ろうとしましたが、ClassVisitorとMethodVisitorを使用してラムダ式に関連付けられたメソッドに到達する以上に進めませんでした。

public <T> List<T> filter(Filter<T> expression) { 
    try { 
     Class<? extends Filter> expressionClass = expression.getClass(); 
     byte[] content = getClassContent(expressionClass); 
     ClassReader classReader = new ClassReader(content); 
     classReader.accept(new PredicateClassVisitor(), 0); 
    } catch (Throwable e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

private byte[] getClassContent(Class<? extends Filter> expressionClazz) throws 
       IOException { 
    InputStream stream = Thread.currentThread().getContextClassLoader() 
          .getResourceAsStream(getClassName(expressionClazz.getName())); 
    return IOUtils.toByteArray(stream); 
} 

private String getClassName(String expressionClazz) { 
    return expressionClazz.substring(0, expressionClazz.indexOf('$')) 
      .replace('.', '/') + ".class"; 
} 

static class PredicateClassVisitor extends ClassVisitor { 

    public PredicateClassVisitor() { 
     super(Opcodes.ASM4); 
    } 

    @Override 
    public MethodVisitor visitMethod(int i, String s, String s2, String s3, 
            String[] strings) { 
     return new PredicateMethodVisitor(); 
    } 
} 

static class PredicateMethodVisitor extends MethodVisitor { 

    public PredicateMethodVisitor() { 
     super(Opcodes.ASM4); 
    } 

    @Override 
    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, 
             Object... bsmArgs) { 
     for (Object object : bsmArgs) { 
       System.out.println(" " + object.toString()); 
     } 
    } 
} 

私はこれが従うべき正しい道ではわからない、とそのような目的のためにASMまたはJDK8でより適切なツールがあった場合、私は思っていました。

何かアドバイスをありがとう;-) 敬具、 ザビエル

+2

実際にここで何を達成しようとしていますか?あなたがこれを説明するまで、あなたに助言するのは難しいです。 –

+0

「取得ラムダ式」とは、「生成する」という意味です。 BTWラムダ呼び出し自体はInvokeDynamicを超えていませんが、これはラムダ呼び出しオブジェクトを作成するプロセスでのみ使用されます。 –

+1

私は、呼び出しコードで提供されたラムダ式をキャプチャしたいと思います。私はJVMの代わりにバイトコードを生成することについて話していません。上記の例から 'filter(Filter expression)'メソッドでは、与えられた 'expression'引数を' person-> person.getAge()> = minAge'ラムダに戻すことができます表現。これは実行可能ですか? –

答えて

4

あなたはすでにあなたがすでにラムダのソースコードを取得するために逆コンパイルするコードを知っているので、ラムダ式は、通常の合成方法にコンパイルされていることを知っている、または、まあ、元のコードに似たもの、あるいは全く違ったものでも、特定のコードに依存します。

ラムダ式の逆コンパイルが他のJava式の逆コンパイルよりも簡単になる理由はありません。シンプルな式は、特にコードにデバッグ情報がある場合、特にコンパイラーが最適化をコードに適用するときに、逆コンパイル時に複雑な式が異なるように見える可能性が高い場合に、容易に回復できます。

+0

どのコードを知っていますか?ラムダクラスの名前(例えば '$$ Lambda $ 58/918965208')は、別々に番号が付けられたラムダメソッドの名前に対応していません。 – OrangeDog

+0

@OrangeDog:そのクラスを逆コンパイルすると、どのメソッドを呼び出すのかが分かります。この質問の場合、OPはインスタンス化サイトを介してメソッドをすでに追跡しています。しかし、この回答のポイントは、それが簡単ではない、または不可能でさえあるということです。 – Holger

+0

インスタンス化サイトをどのように見つけましたか?質問を読んでから、彼らは包囲するクラスに1つのラムダしか持たないので、 'expressionClass'はそのものでなければなりません。 – OrangeDog

0

Groovyでこれを行うことができます。これは、Getting the contents of closure, in groovyに役立ちます。 Gebは実際にこの機能を使用して、評価された式内のアサーションエラーを強調表示します。

関連する問題