2013-12-17 77 views
5

昨晚我在玩Java8 Lambda,並且想知道是否可以在運行時檢索Lambda表達式。總之,據我所知,Lambda表達式在運行時轉換爲(靜態)方法,然後使用InvokeDynamics調用。是否有可能在運行時檢索lambda表達式

讓我們這樣一個例子:

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

其中filter將採取Predicate<T>作爲參數的自定義方法。 在這個filter方法中,我如何在這種情況下以類似於(或相同)的Lambda表達式(person -> person.getAge() >= minAge)的形式檢索參數?

我嘗試使用ASM5_BETA讀取參數類的生成字節碼,但我無法進一步比使用ClassVisitor和MethodVisitor達到與Lambda表達式關聯的方法。

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

通過「檢索lambda表達式」我把它你的意思是「生成」。順便說一下,lambda調用本身並沒有超過InvokeDynamic,這僅用於創建lambda invocator對象的過程中。 –

+1

我想要捕獲調用代碼中提供的Lambda表達式,例如爲了日誌記錄目的或其他用法,也許。我不是在談論生成字節碼而是在生成JVM。從上面給出的例子中,在'filter(Filter expression)'方法中,我希望能夠將給定的'expression'參數恢復爲'person - > person.getAge()> = minAge' lambda表達。這是可行的嗎? –

回答

4

你已經知道,lambda表達式通常被編譯成一種合成方法,所以你已經知道了反編譯得到的拉姆達的源代碼,代碼,或,以及類似於原始代碼的東西,甚至完全不同的東西,這取決於特定的代碼。

沒有理由反編譯lambda表達式比反編譯任何其他Java表達式更容易。簡單表達式可能很容易恢復,特別是當代碼具有調試信息時,複製表達式在反編譯時很可能看起來不同,特別是當編譯器對代碼應用優化時。

+0

你怎麼知道它是哪個代碼? lambda類的名稱(例如'$$ Lambda $ 58/918965208')不對應於單獨編號的lambda方法的名稱。 – OrangeDog

+0

@OrangeDog:如果你反編譯這個類,你會發現它會調用哪個方法。在這個問題的情況下,OP已經通過實例化站點追蹤該方法。然而,這個答案的重點是它不容易,甚至可能是不可能的。 – Holger

+0

他們如何找到實例化網站?從我讀到的問題來看,他們碰巧在封閉類中只有一個lambda,所以'expressionClass'必須是那個。 – OrangeDog

相關問題