2012-02-29 91 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插件的多个执行为我们工作?

相关问题