2013-12-17 3 views
5

पर लैम्ब्डा अभिव्यक्ति को पुनर्प्राप्त करना संभव है, मैं कल रात जावा 8 लैम्ब्डा के साथ खेल रहा था और मैं सोच रहा था कि रनटाइम पर लैम्ब्डा अभिव्यक्ति को पुनर्प्राप्त करना संभव है या नहीं। संक्षेप में और जहां तक ​​मुझे समझा गया, लैम्ब्डा अभिव्यक्ति को रनटाइम पर (स्थैतिक) विधियों में परिवर्तित कर दिया गया और फिर InvokeDynamics का उपयोग करने के लिए कहा जाता है।रनटाइम

के इस तरह एक उदाहरण लेते हैं:

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

जहां filter एक Predicate<T> एक पैरामीटर के रूप लेने के लिए एक कस्टम तरीका होगा। इस filter विधि के अंदर, मैं इस मामले में लैम्ब्डा अभिव्यक्ति (person -> person.getAge() >= minAge) के समान (या समान) रूप में तर्क को कैसे प्राप्त कर सकता हूं?

मैंने एएसएम 5_BETA का उपयोग करके तर्क वर्ग के उत्पन्न बाइटकोड को पढ़ने की कोशिश की लेकिन मैं लैम्बडा अभिव्यक्ति से जुड़े विधि तक पहुंचने के लिए क्लासविजिटर और विधिविज्ञानी का उपयोग करने से आगे नहीं जा सका।

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()); 
     } 
    } 
} 

मुझे यकीन है कि यह सही मार्ग का अनुसरण करने के लिए है नहीं कर रहा हूँ, और अगर वहाँ इस तरह के एक उद्देश्य के लिए एएसएम में या JDK8 में अधिक उपयुक्त टूलींग थे मैं सोच रहा था।

किसी भी सलाह ;-) सादर, जेवियर

+2

आप वास्तव में यहां प्राप्त करने की कोशिश कर रहे हैं? जब तक आप इसे समझा नहीं देते, आपको सलाह देना मुश्किल होता है। –

+0

"लैम्ब्डा अभिव्यक्ति पुनर्प्राप्त करें" द्वारा मैं इसे "उत्पन्न" का मतलब लेता हूं। बीटीडब्ल्यू लैम्बडा कॉल स्वयं InvokeDynamic पर नहीं है, इसका उपयोग केवल लैम्ब्डा इनवोकेटर ऑब्जेक्ट बनाने की प्रक्रिया में किया जाता है। –

+1

मैं लम्बा अभिव्यक्ति को कैप्चर करना चाहता हूं जो कॉलिंग कोड में प्रदान किया गया था, उदाहरण के लिए लॉगिंग उद्देश्य के लिए, या बाद में अन्य उपयोग, शायद। मैं JVM के बजाय बाइटकोड उत्पन्न करने के बारे में बात नहीं कर रहा हूं। ऊपर दिए गए उदाहरण से, 'फ़िल्टर (फ़िल्टर अभिव्यक्ति)' विधि में, मैं दिए गए 'अभिव्यक्ति' को 'व्यक्ति -> person.getAge()> = minAge' lambda पर वापस लाने के लिए सक्षम होना चाहता हूं अभिव्यक्ति। क्या यह करने योग्य है? –

उत्तर

4

आप पहले से ही पता है कि लैम्ब्डा भाव आमतौर पर एक कृत्रिम विधि में संकलित कर रहे हैं ताकि आप पहले से ही जो कोड लैम्ब्डा के स्रोत कोड प्राप्त करने के लिए डिकंपाइल करने के लिए जानते हैं, या के लिए धन्यवाद , ठीक है, विशेष कोड के आधार पर मूल कोड या यहां तक ​​कि कुछ पूरी तरह से अलग दिखने वाला कुछ भी।

कोई अन्य कारण नहीं है कि लैम्ब्डा अभिव्यक्ति को अपनाने का कोई अन्य जावा अभिव्यक्ति को कम करने से आसान क्यों होना चाहिए। सरल अभिव्यक्तियों को पुनर्प्राप्त करना आसान हो सकता है, विशेष रूप से जब कोड में डीबगिंग जानकारी होती है, तो जटिल अभिव्यक्तियों को अलग करने की संभावना बहुत कम होती है, खासकर जब संकलक कोड पर अनुकूलन लागू करता है।

+0

आप कैसे जानते हैं कि यह कौन सा कोड है? लैम्ब्डा वर्ग का नाम (उदा। '$$ लैम्ब्डा $ 58/918 9 65208') लैम्ब्डा विधियों के नाम से मेल नहीं खाता है, जिन्हें अलग से गिने जाते हैं। – OrangeDog

+0

@ ऑरेंजडॉग: यदि आप उस वर्ग को विघटित करते हैं, तो आप पाएंगे कि यह किस विधि का आह्वान करेगा। इस सवाल के मामले में, ओपी ने तत्काल साइट के माध्यम से विधि को ट्रैक कर लिया है। हालांकि, इस जवाब का मुद्दा यह है कि यह * आसान नहीं है या असंभव भी हो सकता है। – Holger

+0

उन्हें तत्काल साइट कैसे मिली है? प्रश्न के मेरे पढ़ने से वे संलग्न वर्ग में केवल एक लैम्ब्डा होते हैं, इसलिए 'अभिव्यक्ति क्लास' वह होना चाहिए। – OrangeDog

0

आप ग्रोवी के साथ कुछ मामलों में ऐसा कर सकते हैं, अगर इससे आपकी मदद मिलेगी: Getting the contents of closure, in groovyGeb वास्तव में मूल्यांकन की गई अभिव्यक्ति के अंदर एक दावा त्रुटि को हाइलाइट करने के लिए इस सुविधा का उपयोग करता है।