2013-05-08 6 views
8

संक्षेप में: 1. मेरे पास कुछ अंतिम वर्ग है जो मैं इसके लिए गतिशील प्रॉक्सी बनाना चाहता हूं। मैं यह कैसे कर सकता हूं? 2. क्या मैं मेथडहैंडल को विधि में परिवर्तित कर सकता हूं?मैं अंतिम कक्षा के लिए गतिशील प्रॉक्सी कैसे बना सकता हूं?

विवरण सबसे पहले, मेथडहैंडल को विधि में बदलने के लिए कोई एपीआई मौजूद है? Java.lang.invoke.MethodHandles में कुछ पसंद है

public MethodHandle unreflect(Method m) throws IllegalAccessException; 

लेकिन विपरीत तरीका arrond?

मान लें कि मैं गतिशील java.lang.reflect.Method बनाना चाहता हूं। यह

public final 
    class Method extends AccessibleObject implements GenericDeclaration, 
               Member ; 

तो जैसा कि defiend है, अगर मैं JDK गतिशील प्रॉक्सी का उपयोग करने मैं कुछ इंटरफेस का उपयोग करना चाहिए (उदाहरण के लिए सदस्य) चाहते हैं। यद्यपि वहाँ 2 मुख्य drawabacks। सबसे पहले, विधि जैसे

public Class<?>[] getParameterTypes(); 

और

public Class<?> getReturnType(); 

जैसे जब वे बड़े पैमाने पर इस्तेमाल कर रहे हैं, किसी भी इंटरफ़ेस का हिस्सा नहीं हैं।

दूसरा दोष यह है कि यह ड्रॉप-इन प्रतिस्थापन प्रदान करने में विफल रहता है। यही है, मैं java.lang.reflect.Method की अपेक्षा करने वाले कोड पर अपनी गतिशील प्रॉक्सी को पास नहीं कर सकता।

एक और तरीका CGLIB या जावासिस्ट का उपयोग करना है। AFAIK, CGLIB अंतिम कक्षा प्रॉक्सी नहीं कर सकता, है ना? जावासिस्ट प्रॉक्सी अंतिम कक्षा कर सकते हैं? मैं कक्षा से अंतिम पहचानकर्ता को कैसे हटा सकता हूं? AFAIL, Javvassist किसी भी तरह यह कर सकते हैं ...

उत्तर

0

क्षमा करें, क्या आप चाहते हैं नहीं संभव है:

आप ठोस वर्ग के लिए प्रॉक्सी बनाने के लिए, क्योंकि इन पुस्तकालयों गतिशील वर्ग का एक उपवर्ग उत्पन्न CGLIB या Javassist उपयोग कर सकते हैं आप प्रॉक्सी करने की कोशिश कर रहे हैं। final वर्ग को उप-वर्गीकृत नहीं किया जा सकता है, इसलिए आप इस तरह प्रॉक्सी नहीं बना सकते हैं।

PowerMock आप प्रॉक्सी final वर्गों और तरीकों जाने करता है, लेकिन यह क्योंकि यह अपनी विशेष ClassLoader जो कक्षाएं आप के रूप में वे लोड किए जा रहे हैं प्रॉक्सी करना चाहते हैं के बाईटकोड को संशोधित करने के Javassist का उपयोग करता है के तहत अपने परीक्षण चलाता है। (आप उत्पादन में इस तरह की चीज का उपयोग नहीं करना चाहेंगे, आम तौर पर कक्षा के संशोधित "ज़ोंबी" संस्करण के परिणामस्वरूप एक विशिष्ट नकली इकाई परीक्षण चलाने से कहीं अधिक अच्छा नहीं होगा।)

PowerMock दृष्टिकोण यहां काम नहीं करेगा, हालांकि - आप बूटस्ट्रैप क्लासपाथ पर java.lang.reflect.Method प्रॉक्सी करना चाहते हैं, और इसलिए किसी भी PowerMock/Javassist प्रकार टूल से पहले लोड होगा और इसलिए प्रॉक्सीबल नहीं होगा।

9

यह इस बात पर निर्भर करता है कि आपको किस प्रकार की प्रॉक्सी चाहिए। मूल रूप से तीन अपरिवर्तक हैं कि आप इसे कैसे प्राप्त कर सकते हैं, जिनमें से दो उत्पादन कोड में व्यवहार्य हैं। जैसा कि @probrekely ने कहा, cglib या javassist की समस्या यह है कि वे गतिशील रूप से एक उपclass बनाते हैं जो अंतिम कक्षाओं के लिए संभव नहीं है। आप इससे बच सकते हैं:

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

    java -Xverify:none ApplicationName 
    

    हालांकि यह समाधान मैं आपको कम से कम अनुशंसा करता हूं। मैं उत्पादन कोड के लिए इस अपमान का उपयोग नहीं करता लेकिन यह निश्चित रूप से लागू करने का सबसे आसान समाधान है।

  • कक्षाओं से पहले या बाद में लोड किए गए वर्गों से final संशोधक को हटाएं। यह Java agent का उपयोग करके प्राप्त किया जा सकता है। एक जावा एजेंट को कमांड लाइन के माध्यम से या रनटाइम पर Attach API के माध्यम से एप्लिकेशन स्टार्टअप पर इंस्टॉल किया जा सकता है। एएसएम जैसे बाइट कोड टूल के साथ, आप मूल बाइट सरणी को पार्स कर सकते हैं और ब्याज के सभी वर्गों से अंतिम संशोधक को हटा सकते हैं। पहले से लोड किए गए वर्गों को फिर से परिभाषित करना भी संभव है। एक final संशोधक निकालें पुराने वर्ग संस्करणों के साथ संघर्ष पेश नहीं करता है जैसे कि एक पुनर्वितरण हमेशा संभव है।

  • जैसा कि मैंने final संशोधक को हटाने के साथ वर्णित किया है वही करें, लेकिन लोड क्लास को मूल श्रेणी में वास्तव में अपने सभी उपकरण तर्क को फिर से परिभाषित करने के लिए परिभाषित करें। इस aporach सबसे निश्चित रूप से सबसे बड़े प्रयास की आवश्यकता होगी, लेकिन यह आपके उपकरण को अन्य सभी कोड के लिए transperent बना देगा। यह सभी समाधानों का सबसे साफ समाधान होगा।

+0

क्या आप आखिरी विकल्प में अधिक विस्तार से व्याख्या कर सकते हैं? – piotrek

+0

आप उपकरण एपीआई का उपयोग कर कक्षाओं को फिर से परिभाषित कर सकते हैं। कहें, एक वर्ग एक विधि foo परिभाषित करता है। आप विधि बार का नाम बदल सकते हैं और इसे अपनी नई विधि foo से कॉल कर सकते हैं जिसे आपने फिर से परिभाषित किया है –

संबंधित मुद्दे