【问题标题】:Workaround for javac compilation order bug in mavenmaven中javac编译顺序错误的解决方法
【发布时间】:2012-02-29 20:09:33
【问题描述】:

我在 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 参数可以重现该问题。简而言之,为了成功,Actions 类必须始终在使用它的 Program 类之前编译,否则 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 枚举实例上的 run 方法,即使它们都实现了具有该 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");
    }
}

仍然对别人的意见感兴趣。

【问题讨论】:

  • 随着ActionSpec 的引入,它开始工作也就不足为奇了。也许该错误仅限于枚举及其实现的内容。 import 也可能有帮助。
  • 您是否尝试过在枚举中添加public abstract int run(String d); 方法?
  • 应该不需要,因为枚举类实现了接口,并且它的所有实例都包含方法的实现(否则枚举不会编译)。
  • 它适用于 Ubuntu 上的 OpenJDK 1.6.0_23。

标签: java maven javac


【解决方案1】:

我玩了一圈,发现添加了简单的演员表:

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

解决了这个问题。将此枚举作为方法参数作为接口传递也可以解决问题

【讨论】:

  • 同意,这类似于我发现的解决方法,并且是总体上最简单的解决方案。
【解决方案2】:

这是http://bugs.sun.com/view_bug.do?bug_id=6724345中报告的错误

如果您仍在使用 Java 6 编译器,建议的解决方法应该有效。该错误已在 Java 7 中修复。

【讨论】:

    【解决方案3】:

    我会这样做:

    • ActionSpec 接口移动到另一个Maven 项目。我们通常在自己的项目中有接口和公共领域类,例如foo-service-specs
    • 保留实施项目中的其他类,例如foo-service-impl.
    • foo-service-specs 项目作为依赖项包含在 foo-service-impl 中。

    通过这样做,您可以确保编译顺序正常工作,并且它也应该适用于持续集成。

    【讨论】:

    • 仍然不能保证Actions在Program之前编译好,这是问题的关键。
    【解决方案4】:

    尝试多次执行编译器插件。使用default-compile 作为第一个执行 ID 会将新配置添加到 Maven 的默认编译器执行中。在默认执行中使用<includes/> 配置元素首先编译枚举。对于第二次执行,您将使用 <includes><excludes> 的组合,其中 <includes> 将是您的所有代码,而 excludes 将是已编译的枚举。

    我认为这适用于您的示例程序,但我没有对其进行测试。我之前用 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>
    

    【讨论】:

      【解决方案5】:

      我们遇到了同样的问题。 maven compiler 插件的多次执行对我们有用...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多