2012-12-03 65 views
17

我正在嘗試編寫一個annotation processor以在類上插入方法和字段...並且文檔非常稀疏。我沒有走得太遠,我不知道我是否正確接近它。使用註釋處理器替換代碼

處理環境提供了一個Filer對象,該對象具有創建新的源文件和類文件的方便方法。這些工作很好,但後來我試圖弄清楚如何讀取現有的源文件,它提供的所有內容都是「getResource」。所以在我的處理器來實現我這樣做:

@Override 
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
    try { 
     for (TypeElement te : annotations) { 
      for (Element element : roundEnv.getElementsAnnotatedWith(te)) { 
       FileObject in_file = processingEnv.getFiler().getResource(
        StandardLocation.SOURCE_PATH, "", 
        element.asType().toString().replace(".", "/") + ".java"); 

       FileObject out_file = processingEnv.getFiler().getResource(
        StandardLocation.SOURCE_OUTPUT, "", 
        element.asType().toString().replace(".", "/") + ".java"); 

       //if (out_file.getLastModified() >= in_file.getLastModified()) continue; 

       CharSequence data = in_file.getCharContent(false); 

       data = transform(data); // run the macro processor 

       JavaFileObject out_file2 = processingEnv.getFiler().createSourceFile(
        element.asType().toString(), element); 
       Writer w = out_file2.openWriter(); 
       w.append(data); 
       w.close(); 
      } 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 
     processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, e.getMessage()); 
    } 
    return true; 
} 

我的第一個困惑是我不禁覺得element.asType().toString().replace(".", "/") + ".java"(獲取限定的類型名稱,並將其轉換成一個包和源文件路徑)不一個很好的方法來解決這個問題。 API的其餘部分過於工程化,但似乎沒有一種方便的方法來檢索原始源代碼。

真正的問題是編譯器會在輸出目錄中的第二個源文件(「error:duplicate class」)中自發地產生不滿,現在我被卡住了。

我已經編寫了剩下的這部分 - 一個宏詞法分析器和解析器,以及用於計算某些數據和插入字段值和方法的東西 - 但它作爲編譯器之外的初始步驟運行。除了原始文件不能具有.java擴展名(以防止編譯器看到它們)之外,這很好地工作。然後我聽說註釋可以做代碼生成,我認爲它會更加正確和方便,但是我找不到很多指導。

+1

請參閱:http://techbitsfromsridhar.blogspot.ca/2013/02/java-compiler-plug-ins-in-java-8-use.html –

回答

16

註解處理器背後的意圖是允許開發人員添加新類,而不是替換現有類。這就是說,有一個錯誤,允許你添加代碼到現有的類。 Project Lombok已將leveraged添加到編譯的java類中,從而將getter和setter(等等)添加到該類中。

我採取的'取代'方法/領域的方法是擴展或委託給輸入類。這允許您覆蓋/轉移對目標類的調用。

因此,如果這是你的輸入類:

InputImpl.java:

public class InputImpl implmements Input{ 
    public void foo(){ 
     System.out.println("foo"); 
    } 
    public void bar(){ 
     System.out.println("bar"); 
    } 
} 

您可以生成以下爲 「替換」 它:

InputReplacementImpl.java:

public class InputReplacementImpl implmements Input{ 

    private Input delegate; 

    //setup delegate.... 

    public void foo(){ 
     System.out.println("foo replacement"); 
    } 
    public void bar(){ 
     delegate.bar(); 
    } 
} 

這引出了一個問題,你怎麼參考InputReplacementImpl ins tead InputImpl。您可以生成更多的代碼來執行包裝,或者只需調用預期生成的代碼的構造函數。

我不確定你的問題是什麼,但我希望這可以解釋你的問題。

+0

*啊哈!*我想我以前見過龍目島,這也是我沒有理由認爲這是不可能的部分原因。這個答案解釋了編譯器的錯誤,並給了我幾個選擇。我不希望陷入AST黑客行爲,目前,簡單的正則表達式爲我執行代碼查找和替換。因爲原來的課程並不完整和可編譯,因此委託該課程並不適合我的情況。就我所見,註釋API的這種愚蠢的小限制意味着它對我來說並不有用,儘管它很複雜。但現在我知道該怎麼做:不使用註釋!非常感謝您的幫助。 – Boann

+0

當然@Boann,祝你的項目好運。 –