Компиляция Java - есть ли способ сказать компилятору игнорировать части моего кода? - PullRequest
10 голосов
/ 16 сентября 2008

Я поддерживаю приложение Java Swing.

Для обратной совместимости с Java 5 (для компьютеров Apple) мы поддерживаем две кодовые базы: одна с использованием функций Java 6, другая без этих функций.

Код в основном такой же, за исключением 3-4 классов, использующих функции Java 6.

Я хочу просто сохранить 1 кодовую базу. Есть ли способ во время компиляции заставить компилятор Java 5 «игнорировать» некоторые части моего кода?

Я не хочу просто комментировать / раскомментировать части моего кода, в зависимости от версии моего Java-компилятора.

Ответы [ 14 ]

5 голосов
/ 16 сентября 2008

Предложения по использованию пользовательских загрузчиков классов и динамически прокомментированного кода немного недоверчивы, когда речь идет об обслуживании и сохранении здравомыслия того, кто бедную душу подхватит, после того, как вы переместитесь на новые пастбища.

Решение простое. Вытяните затронутые классы в два отдельных независимых проекта - убедитесь, что имена пакетов совпадают, и просто скомпилируйте в jar-файлы, которые затем можно будет использовать в вашем основном проекте. Если вы сохраняете одинаковые имена пакетов и подписи метода, проблем не возникает - просто добавьте любую версию jar, которая вам нужна, в ваш скрипт развертывания. Я хотел бы предположить, что вы запускаете отдельные сценарии сборки или имеете разные цели в одном и том же сценарии - ant и maven могут легко обрабатывать условные файлы и копировать их.

4 голосов
/ 16 сентября 2008

Предполагая, что классы имеют схожую функциональность с различиями в реализации 1,5 против 6,0, вы можете объединить их в один класс. Затем, не редактируя источник, чтобы комментировать / раскомментировать, вы можете положиться на оптимизацию, которую всегда делает компилятор. Если выражение if всегда ложно, код в выражении if не будет включен в компиляцию.

Вы можете создать статическую переменную в одном из ваших классов, чтобы определить, какую версию вы хотите запустить:

public static final boolean COMPILED_IN_JAVA_6 = false;

И затем затронутые классы проверяют эту статическую переменную и помещают различные разделы кода в простой оператор if

if (VersionUtil.COMPILED_IN_JAVA_6) {
  // Java 6 stuff goes here
} else {
  // Java 1.5 stuff goes here
}

Затем, когда вы хотите скомпилировать другую версию, вам просто нужно изменить эту переменную и перекомпилировать. Это может увеличить размер файла Java, но консолидирует ваш код и устранит любое дублирование кода. Ваш редактор может жаловаться на недоступный код или что-то еще, но компилятор должен блаженно его игнорировать.

4 голосов
/ 16 сентября 2008

Я думаю, что лучшим подходом здесь, вероятно, является использование сценариев сборки. Вы можете хранить весь свой код в одном месте, и, выбирая, какие файлы включать, а какие не включать, вы можете выбрать, какую версию вашего кода компилировать. Обратите внимание, что это может не помочь, если вам нужен более детальный контроль, чем для каждого файла.

3 голосов
/ 16 сентября 2008

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

public interface Opener{

public void open(File f);

 public static class Util{
        public Opener getOpener(){
          if(System.getProperty("java.version").beginsWith("1.5")){
           return new Java5Opener();
          }
          try{ 
            return new Java6Opener();
           }catch(Throwable t){
            return new Java5Opener();
           }
        }
 }

}

Это может потребовать значительных усилий в зависимости от того, сколько у вас есть фрагментов кода для конкретной версии.

2 голосов
/ 16 сентября 2008

Сохраните один «главный» исходный корень, который собирается под JDK 5. Добавьте второй параллельный исходный корень, который должен быть собран под JDK 6 или выше. (Не должно быть перекрытия, т. Е. В обоих классах не должно быть классов.) Используйте интерфейс, чтобы определить точку входа между ними, и немного отражения.

Например:

---%<--- main/RandomClass.java
// ...
if (...is JDK 6+...) {
    try {
        JDK6Interface i = (JDK6Interface)
            Class.forName("JDK6Impl").newInstance();
        i.browseDesktop(...);
    } catch (Exception x) {
        // fall back...
    }
}
---%<--- main/JDK6Interface.java
public interface JDK6Interface {
    void browseDesktop(URI uri);
}
---%<--- jdk6/JDK6Impl.java
public class JDK6Impl implements JDK6Interface {
    public void browseDesktop(URI uri) {
        java.awt.Desktop.getDesktop().browse(uri);
    }
}
---%<---

Вы можете настроить их как отдельные проекты в IDE, используя разные JDK и т. Д. Дело в том, что основной корень может быть скомпилирован независимо, и очень ясно, что вы можете использовать в каком корне, тогда как если вы пытаетесь компилировать разные части одного корня по отдельности слишком легко случайно «просочить» использование JDK 6 в неправильные файлы.

Вместо того, чтобы использовать Class.forName, как это, вы также можете использовать какую-то систему регистрации служб - java.util.ServiceLoader (если main может использовать JDK 6 и вам нужна дополнительная поддержка JDK 7!), NetBeans Lookup, Spring и т. д. и т. д.

Тот же метод можно использовать для создания поддержки дополнительной библиотеки, а не более новой JDK.

1 голос
/ 17 сентября 2008

Вы можете выполнять всю свою компиляцию исключительно на Java6, а затем использовать System.getProperty ("java.version") для условного запуска пути кода Java5 или Java6.

Вы можете иметь код только для Java6 в классе, и класс будет нормально работать на Java5, если путь кода только для Java6 не выполняется.

Это уловка, которая используется для написания апплетов, которые будут работать на древней MSJVM вплоть до совершенно новых JVM-модулей Java Plug-in.

1 голос
/ 16 сентября 2008

Это зависит от того, какие функции Java 6 вы хотите использовать. Для простой вещи, такой как добавление сортировщиков строк в JTables, вы можете протестировать во время выполнения:

private static final double javaVersion =
         Double.parseDouble(System.getProperty("java.version").substring(0, 3));
private static final boolean supportsRowSorter =
         (javaVersion >= 1.6);

//...

if (supportsRowSorter) {
    myTable.setAutoCreateRowSorter(true);
} else {
    // not supported
}

Этот код должен быть скомпилирован с Java 6, но может быть запущен с любой версией (новые классы не указаны).

РЕДАКТИРОВАТЬ: чтобы быть более правильным, он будет работать с любой версией начиная с версии 1.3 (согласно этой странице ).

1 голос
/ 16 сентября 2008

Это заставит всех Java-пуристов съежиться (что забавно, хе-хе), но я бы использовал препроцессор C, поместив #ifdefs в мой источник. Makefile, rakefile или все, что контролирует вашу сборку, должно запустить cpp, чтобы создать временные файлы для подачи в компилятор. Я понятия не имею, можно ли заставить муравья сделать это.

Хотя stackoverflow выглядит так, как будто он будет местом для всех ответов, вы не могли бы никого отвести от ума до http://www.javaranch.com для мудрости Java. Я полагаю, что этот вопрос уже давно решался.

1 голос
/ 16 сентября 2008

Не совсем, но есть обходные пути. Увидеть http://forums.sun.com/thread.jspa?threadID=154106&messageID=447625

Тем не менее, вы должны придерживаться хотя бы одной версии файла для Java 5 и одной для Java 6 и включать их через сборку или сборку в зависимости от ситуации. Сложить все в один большой файл и попытаться заставить компилятор на 5 игнорировать вещи, которые он не понимает, не является хорошим решением.

НТН

- Никки -

0 голосов
/ 28 сентября 2008

Вы можете использовать API отражения. поместите все свои 1.5 кода в одном классе и 1.6 API в другом. В вашем скрипте ant создайте две цели: одну для 1.5, которая не скомпилирует класс 1.6, и одну для 1.6, которая не скомпилирует класс для 1.5. в вашем коде проверьте версию Java и загрузите соответствующий класс, используя отражение, чтобы javac не жаловался на отсутствующие функции. Вот как я могу скомпилировать свои приложения MRJ (Mac Runtime для Java) в Windows.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...