我遇到了Java编译器中的一个错误,其中提交用于编译的文件的顺序可能导致代码无法编译。我已经深入研究了代码,以找出可以重现问题的最少量代码,从而产生three source files(每个1个类)。
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参数可以重现该问题。简而言之,为了成功,必须始终在使用它的Program类之前编译Actions类,否则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
编译错误发生时始终是相同的 - 即使它们都实现了具有该run方法的接口,也无法找到Actions枚举实例上的run方法。
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 :(得分:5)
我玩了一遍,发现添加了简单的演员:
public static void main(String[] args) {
((ActionSpec)Actions.SKIP).run("hello");
}
解决了这个问题。将此枚举作为方法参数作为接口传递也可以实现技巧
答案 1 :(得分:4)
这是http://bugs.sun.com/view_bug.do?bug_id=6724345
中报告的错误如果您仍在使用Java 6编译器,则建议的解决方法应该可行。该错误已在Java 7中修复。
答案 2 :(得分:0)
我将如何做到这一点:
ActionSpec
界面移至另一个Maven项目。我们通常在他们自己的项目中有接口和公共域类,例如foo-service-specs
。foo-service-impl
。foo-service-specs
。{/ li>中包含foo-service-impl
项目作为依赖项
通过这样做,您可以确保编译顺序正常工作,并且它也可以用于持续集成。
答案 3 :(得分:0)
尝试多次执行编译器插件。使用default-compile
作为第一个执行ID,将新配置添加到Maven的默认编译器执行中。使用默认执行中的<includes/>
config元素首先编译枚举。对于第二次执行,您使用<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>
答案 4 :(得分:0)
我们遇到了同样的问题。 maven compiler
插件的多次执行对我们有用......