2011-01-31 23 views
12

का उपयोग करके एक विधि संशोधित करें जावा में कोई विधि क्या कर रही है मैं कैसे बदल सकता हूं?एनोटेशन

मेरा मतलब है, मैं में

public class TestClass 
{ 
    private static StaticReference z; 

    public void test() 
    { 
      z.invokeToAll(); 
    } 

} 

यह मुझे क्या करना है कोशिश कर रहा हूँ की एक बहुत ही सरल उदाहरण है निम्नलिखित कोड

@Anno1(Argument = "Option1") 
public class TestClass 
{  
    @Anno2 
    public void test() 
    { 
    } 

} 

बनाने के लिए एनोटेशन का उपयोग करने की कोशिश कर रहा हूँ। Anno1 में कई संभावित संयोजन होंगे, लेकिन यह अब तक मेरी समस्या नहीं है। मेरी समस्या यह है कि विधि test()

पर कोड जोड़ने का तरीका है, यदि संभव हो तो मैं अधिक सामान्य समाधान की तलाश में हूं। उदाहरण के लिए। एक तरह से विधि में कोड के हर तरह जोड़ने के लिए (न सिर्फ .invokeToAll() के लिए एक रास्ता)

अब तक मैं import javax.annotation.processing.*; उपयोग कर रहा हूँ और मैं निम्नलिखित कोड है, लेकिन मैं कैसे वहाँ

से पर जाने के लिए पता नहीं है
private void processMethodAnnotations(RoundEnvironment env) 
{ 
    for (Element e : env.getElementsAnnotatedWith(Anno2.class)) 
    { 
     //If it is a valid annotation over a method 
     if (e.getKind() == ElementKind.METHOD) 
     { 
      //What to do here :S 
     }else 
     { 
      processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING,"Not a method!", e);    
     }   
    } 
} 

मुझे जावा प्रतिबिंब के बारे में कुछ मिला है लेकिन मुझे जो भी कर रहा है, उसके साथ मुझे मदद करने के लिए कोई स्रोत नहीं मिला है।

जाहिर है मेरे कोड में

मैं extends AbstractProcessor

मैं इस ट्यूटोरियल पाया है (http://www.zdnetasia.com/writing-and-processing-custom-annotations-part-3-39362483.htm) लेकिन इस एक विधि को बदलने न सिर्फ एक नई कक्षा बनाने की चिंताओं। और javax.lang.model.elements उस तत्व को संपादित करने का कोई भी तरीका प्रदान नहीं करता है (जो मेरे मामले में एक विधि का प्रतिनिधित्व करता है)।

मुझे आशा है कि मेरा प्रश्न नियमों के साथ स्पष्ट और इनलाइन है। यदि नहीं, तो कृपया टिप्पणी करें और मैं स्पष्टीकरण दूंगा। धन्यवाद।

उत्तर

12

एनोटेशन प्रसंस्करण Wikipedia से, आप के लिए जाने के लिए गलत तरीका है:

जब जावा स्रोत कोड संकलित किया गया है, एनोटेशन संकलक प्लग इन एनोटेशन प्रोसेसर बुलाया द्वारा संसाधित किया जा सकता है। प्रोसेसर सूचनात्मक संदेशों उत्पादन कर सकते हैं या अतिरिक्त जावा स्रोत फ़ाइलें या संसाधन बनाने, बारी में संकलित और प्रसंस्कृत हो सकता है, लेकिन एनोटेशन प्रोसेसर एनोटेट कोड में ही संशोधित नहीं कर सकते।

लोगों ने आपको सही तरीके से सुझाव दिया - एओपी। विशेष रूप से आप AspectJ का उपयोग कर सकते हैं। (यदि आप ग्रहण का उपयोग करें) "त्वरित परिणाम" तरीका है:

1) स्थापित करें AJDT (AspectJ विकास उपकरण)
2) AspectJ परियोजना बनाएँ और वहाँ अपनी कक्षाओं और एनोटेशन
3 जोड़ने) बनाएं पहलू:

public aspect Processor { 

    private StaticReference z; 

    pointcut generic() 
      // intercept execution of method named test, annotated with @Anno1 
      // from any class type, annotated with @Anno2 
     : execution(@Anno2 * (@Anno1 *).test()) 
      // method takes no arguments 
     && args(); 

    // here you have write what you want method actually does 
    void around() : generic() { 
     z.invokeToAll(); 
    } 


} 

अब आप एक परीक्षण निष्पादित कर सकते हैं और आपको लगता है कि यह काम करता है देखेंगे;) AJDT आपके लिए अपने आप कोड को संकलित करता है, ऐसा करने के लिए किसी भी शारीरिक श्रम की जरूरत नहीं है, उम्मीद है कि क्या आप "जादू" कहा जाता है;)

अद्यतन:

void around() : generic() { 

    Annotation[] classAnnotations = thisJoinPoint.getThis().getClass().getAnnotations(); 

    String ArgumentValue = null; 
    for (Annotation annotation : classAnnotations) { 
     if (annotation instanceof Anno1) { 
      ArgumentValue = ((Anno1) annotation).Argument(); 
      break; 
     } 
    } 

    if (ArgumentValue != null && ArgumentValue.equals("Option1")) { 
     z.invokeToAll(); 
    } 

} 

जहां thisJoinPoint एक विशेष संदर्भ चर रहा है:

अगर परीक्षण() विधि में अपने कोड Anno1 एनोटेशन मूल्य पर निर्भर करता है, तो पहलू अंदर आप वर्ग एनोटेशन जिसके लिए वह इस तरह से क्रियान्वित किया जाता है प्राप्त कर सकते हैं।

UPDATE2:

आप अपने पहलू में System.out.println(this) जोड़ना चाहते हैं, तो आप वहां System.out.println(thisJoinPoint.getThis()) लिखने के लिए, बस का परीक्षण किया और यह काम करता है की जरूरत है। thisJoinPoint.getThis() आपको "यह" देता है लेकिन बिल्कुल नहीं; वास्तव में यह ऑब्जेक्ट वैरिएबल है और यदि आप किसी भी प्रोपरी को प्राप्त करना चाहते हैं तो आपको या तो प्रतिबिंबित करने या प्रतिबिंब का उपयोग करने की आवश्यकता है। और thisJoinPoint.getThis() निजी संपत्तियों तक पहुंच प्रदान नहीं करता है। ,)

+0

बदलने के अधीन हैं, आप समाधान चाहते हैं कि मैं जो चाहता हूं, दुर्भाग्य से अजीब कारणों से मैं इसका उपयोग नहीं कर सकता। मुझे कहीं और समाधान मिला है ('जावासिस्ट')। वैसे भी मैंने आपको पहले ही +1 और अब प्रयास और अच्छे उत्तर के लिए एक स्वीकृत उत्तर दिया है। आपका बहुत बहुत धन्यवाद! – Muggen

+0

@Muggen एचएम, आप मुझे "अजीब कारणों" के बारे में बता सकते हैं, इसलिए मैं देख सकता था कि वे वास्तव में मायने रखते हैं; शायद एओपी के साथ चिपकने का एक और तरीका है (यह समर्थन करना आसान लगता है ..) – Maxym

+0

उन अजीब कारणों से 'अकादमिक प्रतिबंध' हैं;)। यद्यपि कि आपकी इस सहायता के लिए धन्यवाद। – Muggen

1

ठीक है, आप देख सकते हैं यदि निम्न बॉयलरप्लेट कोड उपयोगी होगा:

public void magic(Object bean, String[] args) throws Exception { 
    for (Method method : bean.getClass().getDeclaredMethods()) { 
     if (method.isAnnotationPresent(Anno2.class)) { 
      // Invoke the original method 
      method.invoke(bean, args); 
      // Invoke your 'z' method 
      StaticReference.invokeAll(); 
     } 
    } 
} 

एक विकल्प के अपने पहलू उन्मुख प्रोग्रामिंग को रोजगार कर सकते हैं, उदाहरण के लिए आप AspectJ परियोजना है।

+0

एचएम स्मार्ट, लेकिन 'z.invokeToAll() की बजाय क्या होगा; 'उदाहरण के लिए मैं System.out.println (this) जैसे कुछ करने के लिए चाहता हूं;' यदि संभव हो तो मैं अधिक सामान्य समाधान की तलाश में हूं। – Muggen

+0

प्रिंटिंग 'इस' का अर्थ है' TestClass.toString() '। यदि आप चाहें तो भी आप ऐसा कर सकते हैं। इसके अलावा, प्रतिबिंब के साथ, आप अपने एनोटेटेड कक्षाओं के सभी गुणों तक पहुंच सकते हैं। –

1

मुझे यकीन नहीं है कि स्रोत या बाइट कोड को एनोटेशन के माध्यम से बदलना भी संभव है। आपके वर्णन से यह ऐसा लगता है कि aspect oriented programming आपकी समस्या का समाधान प्रदान कर सकता है।

आपका एनोटेशन सुंदर pointcut अवधारणा और डाला कोड करीब है सलाह अवधारणा (जहां कोड डाला जा करने की जरूरत है कि वे एक स्थान चिह्नित) के लिए समान हैं।

एक अन्य दृष्टिकोण जावा स्रोत फ़ाइल को एक अमूर्त वाक्यविन्यास पेड़ में पार्स कर रहा है, इस एएसटी को संशोधित करेगा और जावा कंपाइलर इनपुट को क्रमबद्ध करेगा।

+1

एओपी यहां जाने का तरीका है (+1)। एएसटी को संशोधित करना संभव है (मैंने इसे सफलतापूर्वक किया है), लेकिन यह एक गंदे हैक है जो अनियंत्रित आंतरिक एपीआई पर निर्भर करता है जो –

0

यदि आपकी कक्षा एक उपयुक्त इंटरफ़ेस फैली हुई है, तो आप इसे एक डायनामिकप्रॉक्सी में लपेट सकते हैं, जो कॉल करने के लिए कॉल को छोड़कर मूल विधियों को सभी कॉल का प्रतिनिधित्व करता है।

3

यह आप क्या पूछना करने के लिए पूरी तरह से संभव है, पूछने के लिए स्वतंत्र महसूस हो रहा है -

खैर, अब लगता है कि आपके सवाल का जवाब है, लेकिन अगर मैं कुछ भी याद किया, या आप इस तरह के साथ अतिरिक्त प्रश्न/समस्याओं मिल हालांकि एक चेतावनी है: निजी कंपाइलर एपीआई पर निर्भर है। डरावना लगता है, लेकिन यह वास्तव में नहीं है (कंपाइलर कार्यान्वयन स्थिर होते हैं)।

एक पेपर है जो प्रक्रिया को समझाता है: The Hacker's Guide to Javac

विशेष रूप से, यह स्वचालित गेटर/सेटर पीढ़ी (अन्य चीजों के साथ) प्रदान करने के लिए Project Lombok द्वारा उपयोग किया जाता है। following article बताता है कि यह कैसे करता है, मूल रूप से उपरोक्त पेपर कहलाता है।