2016-07-20 6 views
5

में मल्टी-मॉड्यूल एनोटेशन प्रोसेसिंग मेरे पास एंड्रॉइड स्टूडियो में एकाधिक मॉड्यूल के साथ एक प्रोजेक्ट है। > मॉड्यूल FeatureOne - -> मॉड्यूल सेवाएंएंड्रॉइड स्टूडियो

मैं जड़ मॉड्यूल में मेरी टिप्पणी के प्रसंस्करण को शामिल किया है लेकिन एंड्रॉयड-उपयुक्त एनोटेशन प्रसंस्करण होता है

मॉड्यूल PhoneApp: एक मॉड्यूल उदाहरण के लिए, एक और मॉड्यूल पर निर्भरता हो सकता है केवल शीर्षतम स्तर (फोन ऐप) पर, ताकि सैद्धांतिक रूप से संकलन समय पर सभी मॉड्यूल तक पहुंच हो। हालांकि, जेनरेट की गई जावा फाइल में जो कुछ मैं देख रहा हूं वह केवल फोन ऐप में एनोटेटेड कक्षाओं और अन्य मॉड्यूल से कोई नहीं है।

PhoneApp/build/generated/source/apt/debug/.../GeneratedClass.java 

अन्य मॉड्यूल में, मैं मध्यवर्ती निर्देशिका कि कि मॉड्यूल से केवल टिप्पणी सहित फ़ाइलें हैं में एक उत्पन्न फ़ाइल लग रहा है।

FeatureOne/build/intermediates/classes/debug/.../GeneratedClass.class 
FeatureOne/build/intermediates/classes/debug/.../GeneratedClass.java 

मेरा लक्ष्य है कि मुझे सभी मॉड्यूल से एनोटेट फ़ाइलों तक पहुँचने के लिए अनुमति देता PhoneApp में एक भी उत्पन्न फ़ाइल है। पूरी तरह से सुनिश्चित नहीं है कि प्रत्येक के लिए कोड जनरेशन प्रक्रिया क्यों चल रही है और फ़ोन ऐप पर सभी एनोटेशन को एकत्र करने में विफल रही है। किसी भी मदद की सराहना की।

कोड काफी सरल है और सीधे आगे अब तक, checkIsValid() लोप इसे सही ढंग से काम करता है के रूप में:

एनोटेशन प्रोसेसर:

@Override 
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
    try { 

     for (Element annotatedElement : roundEnv.getElementsAnnotatedWith(GuiceModule.class)) { 
      if (checkIsValid(annotatedElement)) { 
       AnnotatedClass annotatedClass = new AnnotatedClass((TypeElement) annotatedElement); 
       if (!annotatedClasses.containsKey(annotatedClass.getSimpleTypeName())) { 
        annotatedClasses.put(annotatedClass.getSimpleTypeName(), annotatedClass); 
       } 
      } 
     } 

     if (roundEnv.processingOver()) { 
      generateCode(); 
     } 

    } catch (ProcessingException e) { 
     error(e.getElement(), e.getMessage()); 
    } catch (IOException e) { 
     error(null, e.getMessage()); 
    } 

    return true; 
} 

private void generateCode() throws IOException { 
    PackageElement packageElement = elementUtils.getPackageElement(getClass().getPackage().getName()); 
    String packageName = packageElement.isUnnamed() ? null : packageElement.getQualifiedName().toString(); 

    ClassName moduleClass = ClassName.get("com.google.inject", "Module"); 
    ClassName contextClass = ClassName.get("android.content", "Context"); 
    TypeName arrayOfModules = ArrayTypeName.of(moduleClass); 

    MethodSpec.Builder methodBuilder = MethodSpec.methodBuilder("juice") 
      .addParameter(contextClass, "context") 
      .addModifiers(Modifier.PUBLIC, Modifier.STATIC) 
      .returns(arrayOfModules); 

    methodBuilder.addStatement("$T<$T> collection = new $T<>()", List.class, moduleClass, ArrayList.class); 

    for (String key : annotatedClasses.keySet()) { 

     AnnotatedClass annotatedClass = annotatedClasses.get(key); 
     ClassName className = ClassName.get(annotatedClass.getElement().getEnclosingElement().toString(), 
       annotatedClass.getElement().getSimpleName().toString()); 

     if (annotatedClass.isContextRequired()) { 
      methodBuilder.addStatement("collection.add(new $T(context))", className); 
     } else { 
      methodBuilder.addStatement("collection.add(new $T())", className); 
     } 

    } 

    methodBuilder.addStatement("return collection.toArray(new $T[collection.size()])", moduleClass); 

    TypeSpec classTypeSpec = TypeSpec.classBuilder("FreshlySqueezed") 
      .addModifiers(Modifier.PUBLIC, Modifier.FINAL) 
      .addMethod(methodBuilder.build()) 
      .build(); 

    JavaFile.builder(packageName, classTypeSpec) 
      .build() 
      .writeTo(filer); 
} 

यह सिर्फ एनोटेशन प्रसंस्करण का एक डेमो है कि Guice के साथ काम करता के लिए है , अगर कोई उत्सुक है।

तो मैं सभी एनोटेटेड कक्षाओं को सभी मॉड्यूल से उत्पन्न फ़ोन ऐप .java फ़ाइल में शामिल करने के लिए कैसे प्राप्त कर सकता हूं?

+0

यह एक अच्छा सवाल है।मुझे लगता है कि जब भी आप इसे पाते हैं तो अपना समाधान साझा करते हैं तो बहुत से लोग सराहना करेंगे, मैंने अभी तक नहीं किया है। [डीबीएफएलओ परियोजना मुद्दों अनुभाग] (https://github.com/Raizlabs/DBFlow/issues/266) में प्रोसेसर प्रतिबंधों के बारे में एक चर्चा है, जिसे एक प्रमाण के रूप में माना जा सकता है कि वांछित क्रॉस- मॉड्यूल एनोटेशन प्रोसेसर। – konata

+0

चूंकि एनोटेशन प्रोसेसर अलग-अलग मॉड्यूल के लिए अलग-अलग चलता है, इसलिए आप वृद्धिशील दृष्टिकोण को आजमा सकते हैं, लेकिन यह आपके मामले पर थोड़ा निर्भर करता है। यदि आप अगले मॉड्यूल को संसाधित करने के बाद पूरी कक्षा को बदलने की जरूरत नहीं है, तो यह काम कर सकता है, लेकिन मौजूदा वर्ग में केवल नई लाइनें जोड़ें: 1. पहली मॉड्यूल को प्रोसेस करते समय, निर्दिष्ट स्थान पर अपनी कक्षा उत्पन्न करें (कहीं PhonApp मॉड्यूल के ** उत्पन्न ** पेड़); 2. अगले मॉड्यूल को संसाधित करते समय, जांचें कि जेनरेट क्लास मौजूद है या नहीं और इसमें नया कोड जोड़ें। – konata

+0

चूंकि यह एक प्रेजेंटेशन में सिर्फ एक डेमो था, इसलिए मैंने समाधान की तलाश जारी नहीं रखी। (विचार किया गया कि सवाल उठता है कि जेनरेट की गई फाइल में सभी मॉड्यूल डेटा क्यों शामिल नहीं किए गए थे) मैंने प्रत्येक मॉड्यूल से जेनरेट की गई फ़ाइलों की प्रतिलिपि बनाने के लिए ग्रैडल कार्यों का उपयोग करने पर विचार किया था, लेकिन ऐसे समाधान को पसंद करेंगे जिन्हें बिल्ड टूल्स पर भरोसा करने की आवश्यकता नहीं होगी । – fakataha

उत्तर

0

जेनरेट की गई फ़ाइल को सहेजने के लिए फ़िलर का उपयोग करने के बजाय, नियमित जावा फ़ाइल लेखन का उपयोग करें। प्रोसेस करते समय आपको ऑब्जेक्ट को temp फ़ाइलों में क्रमबद्ध करने की आवश्यकता होगी क्योंकि स्थिर चर भी मॉड्यूल के बीच में सहेज नहीं पाएंगे। संकलन से पहले temp फ़ाइलों को हटाने के लिए gradle कॉन्फ़िगर करें।

0

यह इतने पर एक सवाल का जवाब देने में कभी देर नहीं है, तो ...

मैं काम पर कार्यों में से एक के दौरान एक बहुत समान जटिलता का सामना करना पड़ा है।

और मैं इसे हल करने में सक्षम था।

लघु संस्करण

तुम सब moduleA में moduleB से उत्पन्न कक्षाओं के बारे में पता करने की जरूरत पैकेज और वर्ग के नाम है। जिसे ज्ञात पैकेज में रखे गए MyClassesRegistrar जेनरेटेड क्लास में संग्रहीत किया जा सकता है। नामों से छेड़छाड़ से बचने के लिए प्रत्यय का प्रयोग करें, पैकेज द्वारा रजिस्ट्रार प्राप्त करें। उन्हें तत्काल करें और उनसे डेटा का उपयोग करें।

Lond संस्करण

सबसे पहले - आप न केवल सर्वोच्च मॉड्यूल पर अपने ही संकलन समय-निर्भरता को शामिल करने में सक्षम हो जाएगा (की सुविधा देता है यह "एप्लिकेशन" मॉड्यूल फोन के रूप में अपने ठेठ एंड्रॉयड परियोजना संरचना करता है) । एनोटेशन प्रसंस्करण सिर्फ उस तरह से काम नहीं करता है, और जहां तक ​​मुझे पता चल सकता है - इसके बारे में कुछ भी नहीं किया जा सकता है।

अब विवरण के लिए।मेरा काम यह था: मेरे पास मानव लिखित एनोटेटेड कक्षाएं हैं। मैं उन्हें "घटनाओं" नाम दूंगा। संकलन समय पर मुझे उन घटनाओं के लिए अपनी संरचना और सामग्री (स्थिर रूप से उपलब्ध (एनोटेशन वैल्यू, कॉन्स, इत्यादि) और रनटाइम दोनों को शामिल करने के लिए सहायक वर्गों को उत्पन्न करने की आवश्यकता है (मैं बाद में उपयोग करते समय उन सहायकों को ईवेंट ऑब्जेक्ट्स पास कर रहा हूं)। वर्ग के नाम एक प्रत्यय के साथ घटना वर्ग के नाम पर निर्भर करता है इसलिए मैंने इसे जब तक कोड पीढ़ी समाप्त हो गया पता नहीं है।

तो बाद सहायकों उत्पन्न कर रहे हैं मैं एक कारखाने बना सकते हैं और नए सहायक MyEvent.class प्रदान की के आधार पर उदाहरण प्रदान करने के लिए कोड उत्पन्न करते हैं। यहाँ समस्या: मुझे केवल ऐप मॉड्यूल में एक कारखाने की आवश्यकता है, लेकिन यह लाइब्रेरी मॉड्यूल से ईवेंट के लिए हेल्पर्स प्रदान करने में सक्षम होना चाहिए - इसे सीधे नहीं किया जा सकता है।

मैंने जो किया था:

  1. मॉड्यूल के लिए जेनरेटिंग फैक्ट्री छोड़ें जो मेरा ऐप मॉड्यूल निर्भर करता है;

  2. गैर एप्लिकेशन मॉड्यूल में

    एक तथाकथित HelpersRegistrar कार्यान्वयन (रों) उत्पन्न:

    - वे सभी शेयर एक ही पैकेज (आप क्यों बाद में पता चल जाएगा);

    - उनके नाम प्रत्यय (नीचे देखें) के कारण संघर्ष नहीं करते हैं;

    - ऐप मॉड्यूल और लाइब्रेरी-मॉड्यूल के बीच भेदभाव javac "-Amylib.suffix=MyModuleName" परम के माध्यम से किया जाता है, उपयोगकर्ता को सेट करना होगा - यह एक सीमा है, लेकिन एक मामूली है। ऐप मॉड्यूल के लिए कोई प्रत्यय निर्दिष्ट नहीं किया जाना चाहिए;

    - हेल्पर्स रजिस्ट्रार उत्पन्न कार्यान्वयन भविष्य में फैक्ट्री कोड उत्पन्न करने के लिए मुझे आवश्यक सभी प्रदान कर सकता है: इवेंट क्लास नाम, सहायक वर्ग का नाम, पैकेज (सहायक और घटना के बीच पैकेज-दृश्यता के लिए ये दो शेयर पैकेज) - पीओजेओ में शामिल सभी स्ट्रिंग्स;

  3. ऐप मॉड्यूल में मैं मददगार उत्पन्न करता हूं - सामान्य रूप से, फिर मैं उनके पैकेज द्वारा हेल्पर रेग्रिस्टर्स प्राप्त करता हूं, उन्हें तुरंत चालू करता हूं, अपने कारखाने को कोड के साथ समृद्ध करने के लिए अपनी सामग्री के माध्यम से चलाता हूं जो अन्य मॉड्यूल से मददगार प्रदान करता है। इसके लिए मुझे कक्षा के नाम और पैकेज की आवश्यकता थी।

  4. वोला! मेरा कारखाना ऐप मॉड्यूल और अन्य मॉड्यूल से दोनों मददगार प्रदान कर सकता है।

केवल एक ही अनिश्चितता ऐप मॉड्यूल में और अन्य मॉड्यूल में प्रोसेसर-क्लास उदाहरण बनाने और चलाने का क्रम है। मुझे इस पर कोई ठोस जानकारी नहीं मिली है, लेकिन मेरे उदाहरण को चलाने से पता चलता है कि कंपाइलर (और इसलिए, कोड जनरेशन) पहले मॉड्यूल में चलता है जिसे हम निर्भर करते हैं, और फिर - ऐप मॉड्यूल में (अन्यथा ऐप मॉड्यूल का संकलन एफ होगा। .cked)। यह हमें विभिन्न मॉड्यूल में कोड प्रोसेसर निष्पादन के ज्ञात क्रम की अपेक्षा करने का कारण देता है।

एक और, थोड़ा समान, दृष्टिकोण यह है: रजिस्ट्रार छोड़ें, सभी मॉड्यूल में कारखानियां उत्पन्न करें और अन्य कारखानों का उपयोग करने के लिए ऐप मॉड्यूल में फैक्ट्री लिखें, जो आपको उपरोक्त रजिस्ट्रार के समान ही मिलता है और नाम देता है।

उदाहरण यहां देखा जा सकता है: https://github.com/techery/janet-analytics - यह एक पुस्तकालय है जहां मैंने इस दृष्टिकोण को लागू किया है (रजिस्ट्रार के बिना एक मेरे पास कारखानों के बाद से है, लेकिन यह आपके लिए मामला नहीं हो सकता है)।

पी एस .: प्रत्यय परम सरल "-Amylibraryname.library = सच" और कारखानों में बदला जा सकता/नाम स्वतः जेनरेट की जा सकती है, रजिस्ट्रार/वृद्धि

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