2012-02-29 61 views
18

我在Java編譯器中遇到了一個錯誤,其中提交編譯的文件順序可能導致代碼無法編譯。我已經深入瞭解代碼,以隔離可以重現問題的最小代碼量,從而得到three source files(每個類都有1個類)。用於maven的javac編譯命令錯誤的解決方法

public interface ActionSpec { 
    public abstract int run(String param); 
} 


public enum Actions implements ActionSpec { 
    SKIP { 
     public int run(String d) { 
      return 0; 
     } 
    }; 
} 

public class Program { 

    public static void main(String[] args) { 
     Actions.SKIP.run("hello"); 
    } 
} 

該問題可以通過以特定順序擁有javac參數來重現。總之,要想出人頭地,動作類必須始終,它使用它的程序前級編譯,否則javac的只是不能以理智的方式來對付它:當它發生時

# this case fails 
echo "Trying order: javac Program.java Actions.java ActionSpec.java" 
rm *class 
javac -verbose Program.java Actions.java ActionSpec.java 

# this case fails 
#rm *class 
#javac Program.java Actions.java ActionSpec.java 

# this case fails 
#rm *class 
#javac ActionSpec.java Program.java Actions.java 

# this case succeeds 
#rm *class 
#javac ActionSpec.java Actions.java Program.java 

# this case succeeds 
#rm *class 
#javac Actions.java ActionSpec.java Program.java 

# this case succeeds 
#rm *class 
#javac Actions.java Program.java ActionSpec.java 

編譯錯誤, ,始終是相同的 - 即使它們都實現了具有該運行方法的接口,仍無法找到Actions枚舉實例上的運行方法。

Program.java:6: cannot find symbol 
symbol : method run(java.lang.String) 
location: class problem.Actions 
     Actions.SKIP.run("hello"); 

該錯誤似乎與this one reported on Oracle's site有關。 我在mac os x 10.7.2 x86_64上使用javac 1.6.0_29,但也在Linux上轉載了它。

當我使用Maven構建時,此問題變得明顯,並且似乎沒有任何對編譯順序的控制權。所以我正在尋找一種解決方法,迫使maven按照避免編譯器錯誤的順序編譯文件,或者避免使用編譯器標誌(或類似的東西)來避免它。這個問題在工作站和持續集成環境中都會出現,所以它必須全面工作。有什麼建議麼?

編輯:只是嘗試了以下解決方法,儘管只是將問題的枚舉分配給變量與它實現的接口的類型,出人意料地導致錯誤消失。

public class Program { 

    public static void main(String[] args) { 
     ActionSpec a = Actions.SKIP; 
     a.run("hello"); 
    } 
} 

對其他意見仍然感興趣。

+0

引入ActionSpec開始工作並不奇怪。也許這個bug只限於enum和它的實現。 「進口」也可能有幫助。 – 2012-02-29 21:03:27

+0

你有沒有嘗試添加一個'公共抽象int運行(字符串d);'枚舉的方法? – 2012-02-29 21:25:45

+0

應該不需要,因爲枚舉類實現了接口,並且它的所有實例都包含該方法的實現(否則枚舉不會編譯)。 – 2012-02-29 23:06:30

回答

5

我發揮各地,並發現添加簡單的轉換:

public static void main(String[] args) { 
    ((ActionSpec)Actions.SKIP).run("hello"); 
} 

解決了這個問題。通過這個枚舉作爲方法參數作爲接口也會訣竅

+0

同意,這與我發現的解決方法類似,並且是最簡單的整體解決方案。 – 2012-03-12 18:06:51

0

這是我會怎麼做:

  • 移動ActionSpec接口到另一個Maven項目。我們通常在他們自己的項目中有接口和公共領域類,例如foo-service-specs
  • 將其他類保留在實施項目中,例如foo-service-impl
  • foo-service-impl中包含foo-service-specs項目作爲依賴項。

通過這樣做,您可以確保編譯順序正常,並且它也應該用於持續集成。

+0

仍然無法保證Actions在編程之前編譯,這是問題的關鍵。 – 2012-03-09 06:27:25

0

嘗試多次執行編譯器插件。使用default-compile作爲第一個執行ID將新配置添加到Maven的默認編譯器執行中。在默認執行中使用<includes/>配置元素首先編譯枚舉。對於第二次執行,您將使用<includes><excludes>的組合,其中<includes>將是您的所有代碼,排除將是已編譯的枚舉。

我認爲這將適用於您的示例程序,但我沒有測試它。我之前用Maven 3測試過類似的東西,並且它工作正常。

<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-compiler-plugin</artifactId> 
    <version>2.3.2</version> 
    <configuration> 
     <source>1.6</source> 
     <target>1.6</target> 
    </configuration> 
    <executions> 
     <execution> 
      <id>default-compile</id> 
      <goals><goal>compile</goal></goals> 
      <configuration> 
       <includes> 
        <include>**/Actions.*</include> 
       </includes> 
      </configuration> 
     </execution> 
     <execution> 
      <id>second</id> 
      <goals><goal>compile</goal></goals> 
      <configuration> 
       <includes> 
        <include>**/*</include> 
       </includes> 
       <excludes> 
        <exclude>**/Actions.*</exclude> 
       </excludes> 
      </configuration> 
     </execution> 
    </executions> 
</plugin> 
0

我們遇到了同樣的問題。在maven compiler插件的多個執行爲我們工作?

相關問題