Я встречаюсь с ошибкой в компиляторе Java, где порядок файлов, отправленных для компиляции, может привести к тому, что код не будет компилироваться. Я развернул код, чтобы изолировать наименьший объем кода, который мог бы воспроизвести проблему, в результате получилось три исходных файла (по 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 всегда должен быть скомпилирован перед классом программы, который его использует, иначе 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 в экземплярах enum Actions не может быть найден, хотя все они реализуют интерфейс, который имеет этот метод запуска.
Program.java:6: cannot find symbol
symbol : method run(java.lang.String)
location: class problem.Actions
Actions.SKIP.run("hello");
Ошибка, связанная с об этом сообщается на сайте Oracle. Я использую javac 1.6.0_29, на mac os x 10.7.2 x86_64, но также воспроизвел его на Linux.
Эта проблема стала очевидной, поскольку я использую Maven для сборки и, похоже, не контролирую порядок компиляции. Поэтому я ищу обходное решение, чтобы либо заставить maven скомпилировать файлы в таком порядке, чтобы избежать ошибки компилятора, либо возиться с флагами компилятора (или что-то вроде этого), чтобы избежать этого. Проблема возникает на рабочих станциях и в непрерывных средах интеграции, поэтому она должна работать по всем направлениям. Любые предложения?
EDIT: просто попробовал следующее обходное решение, которое, несмотря на то, что просто присваивает рассматриваемое перечисление переменной с типом интерфейса, который она реализует, неожиданно приводит к исчезновению ошибки.
public class Program {
public static void main(String[] args) {
ActionSpec a = Actions.SKIP;
a.run("hello");
}
}
Все еще интересуются мнениями других.