Есть ли способ определить постоянное значение Java во время компиляции

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

С++:

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

Тогда на компиляции я имел в 'build script' -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, но на пути к классам.

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

ИЗМЕНИТЬ

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

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

Ответ 1

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

Это хорошо документированная и понятная спецификация 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, поэтому, вероятно, для последующих разработчиков кода последует легче.

Ответ 2

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

class Version... {
  public static String tstamp() {
    return "@[email protected]";
  }
}

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

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

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

Ответ 3

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

Здесь будет Ant тип.

Ответ 4

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

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

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

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

Ответ 5

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

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

public String getBuildDateTime() {
    return "@[email protected]";
}

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

Ответ 6

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

Ответ 7

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

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