Подтвердить что ты не робот

Обходной путь для ошибки порядка компиляции javac в maven

Я встречаюсь с ошибкой в ​​компиляторе 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");
    }
}

Все еще интересуются мнениями других.

4b9b3361

Ответ 1

Я играл, и обнаружил, что добавление простого актера:

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

решает эту проблему. Передача этого enum в качестве параметра метода как интерфейса также приведет к трюку

Ответ 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.

Сделав это, вы можете убедиться, что порядок компиляции работает, и он также должен работать для непрерывной интеграции.

Ответ 4

Попробуйте выполнить несколько исполнений плагина компилятора. Используя default-compile, поскольку первый идентификатор выполнения добавляет новую конфигурацию к исполнению компилятора 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>

Ответ 5

У нас была та же проблема. Множество исполнений плагина maven compiler работало для нас...