Есть ли способ определить постоянное значение для Java во время компиляции - PullRequest
11 голосов
/ 19 сентября 2008

Когда я писал библиотеки на C / C ++, у меня появилась привычка иметь метод для возврата даты / времени компиляции. Это всегда было скомпилировано в библиотеку, поэтому будет отличаться сборками библиотеки. Я получил это, вернув #define в коде:

C ++:

#ifdef _BuildDateTime_
   char* SomeClass::getBuildDateTime() {
      return _BuildDateTime_;
   }
#else
   char* SomeClass::getBuildDateTime() {
      return "Undefined";
   }
#endif

Затем во время компиляции в сценарии сборки у меня было '-D_BuildDateTime _ = Date'.

Есть ли способ достичь этого или аналогичного в Java, не забывая редактировать какие-либо файлы вручную или распространяя отдельные файлы.

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

Примерно так (при условии, что созданный файл назывался 'DateTime.dat'):

// I know Exceptions and proper open/closing 
// of the file are not done. This is just 
// to explain the point!
String getBuildDateTime() {
    return new BufferedReader(getClass()
            .getResourceAsStream("DateTime.dat")).readLine();
}

На мой взгляд, это взломанный файл, который может быть обойден / сломан кем-то, имеющим файл с таким же именем вне JAR, но на пути к классам.

В любом случае, мой вопрос заключается в том, существует ли какой-либо способ ввести константу в класс во время компиляции

EDIT

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

Мое личное предпочтение будет заключаться в использовании даты из файла JAR, как предложено serg10.

Ответы [ 7 ]

15 голосов
/ 19 сентября 2008

Я бы предпочел подход, основанный на стандартах. Поместите информацию о своей версии (вместе с другими полезными материалами издателя, такими как номер сборки, номер редакции Subversion, автор, данные о компании и т. Д.) В банку Файл манифеста .

Это хорошо документированная и понятная спецификация Java. Существует сильная поддержка инструментов для создания файлов манифеста (например, основная задача Ant или плагин maven jar ). Это может помочь с автоматической настройкой некоторых атрибутов - я настроил maven, чтобы поместить номер версии jar maven, версию Subversion и метку времени в манифест для меня во время сборки.

Вы можете прочитать содержимое манифеста во время выполнения с помощью стандартных вызовов Java API - что-то вроде:

import java.util.jar.*;

...

JarFile myJar = new JarFile("nameOfJar.jar");    // various constructors available
Manifest manifest = myJar.getManifest();
Map<String,Attributes> manifestContents = manifest.getAttributes();

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

11 голосов
/ 19 сентября 2008

Я помню, что видел нечто подобное в проекте с открытым исходным кодом:

class Version... {
  public static String tstamp() {
    return "@BUILDTIME@";
  }
}

в файле шаблона. С помощью фильтрующей копии Ant вы можете задать этому макросу значение:

<copy src="templatefile" dst="Version.java" filtering="true">
    <filter token="BUILDTIME" value="${build.tstamp}" />
</copy>

используйте это для создания исходного файла Version.java в процессе сборки перед этапом компиляции.

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

AFAIK нет способа сделать это с помощью Javac. Это легко сделать с помощью Ant - я бы создал объект первого класса с именем BuildTimestamp.java и сгенерировал бы этот файл во время компиляции через цель Ant.

Вот тип муравья , который будет вам полезен.

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

Возможно, более простым способом указания версии вашей библиотеки в Java будет добавление номера версии в манифест JAR, как описано в документации манифеста .

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

Лично я бы пошел в отдельный файл свойств в вашем банке, который вы загрузите во время выполнения ... Загрузчик классов имеет определенный порядок для поиска файлов - я не могу вспомнить, как он работает точно от руки, но Я не думаю, что другой файл с таким же именем где-нибудь на пути к классам может вызвать проблемы.

Но еще один способ сделать это - использовать Ant для копирования файлов .java в другой каталог перед их компиляцией, при необходимости фильтруя строковые константы. Вы можете использовать что-то вроде:

public String getBuildDateTime() {
    return "@BUILD_DATE_TIME@";
}

и запишите фильтр в файл Ant, чтобы заменить его свойством сборки.

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

Если вы не хотите запускать исходный код Java через препроцессор C / C ++ (который является БОЛЬШИМ-НЕТ-НЕТ), используйте метод jar. Существуют и другие способы получения правильных ресурсов из фляги, чтобы убедиться, что кто-то не поместил дубликат ресурса в путь к классам. Вы также можете рассмотреть возможность использования Jar-манифеста для этого. Мой проект делает именно то, что вы пытаетесь сделать (с датами сборки, ревизиями, автором и т. Д.), Используя манифест.

Вы хотите использовать это:

Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF");

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

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

Одно предложение от коллеги должен был получить файл муравья, чтобы создать файл на пути к классам и для упаковки что в банку и прочитать его метод. ... На мой взгляд, это взломать и можно было обойти / сломать кем-то с таким же именем файл за пределами JAR, но на CLASSPATH.

Я не уверен, что заставить Ant сгенерировать файл - это ужасно вопиющий хак, если это вообще хак. Почему бы не создать файл свойств и использовать java.util.Properties для его обработки?

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