Вопрос по c, c++, java – Есть ли способ определить постоянное значение для Java во время компиляции

11

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

C ++:

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

Затем во время компиляции у меня был -D_BuildDateTime_ =Date& APOS; в сценарии сборки.

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

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

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

<code>// 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();
}
</code>

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

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

РЕДАКТИРОВАТЬ

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

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

To my mind that's a hack and could be circumvented/broken by someone having a similarly named file outside the JAR, but on the classpath.  В какой рабочей среде вы программируете, что вы беспокоитесь о людях, «обходящих»? этот? Наличие Ant для генерации файла - это совсем не хак. Конечно, манифестный подход еще лучше Java-изма (и вы можете использовать Ant для автоматизации). Hejazzman

Ваш Ответ

7   ответов
2

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

Вот тип муравья это будет полезно.

1

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

1

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

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

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

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

1

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

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

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

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

0

One suggestion I got from a co-worker was to get the ant file to create a file on the classpath and to package that into the JAR and have it read by the method. ... To my mind that's a hack and could be circumvented/broken by someone having a similarly named file outside the JAR, but on the classpath.

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

11

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

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 в процессе сборки перед этапом компиляции.

15

I would favour the standards based approach.  Поместите информацию о своей версии (вместе с другими полезными материалами издателя, такими как номер сборки, номер редакции Subversion, автор, данные о компании и т. Д.) В банки.Файл манифеста.

This is a well documented and understood Java specification.  Существует сильная поддержка инструментов для создания файлов манифеста (основная задача Ant например, илиплагин maven jar). Это может помочь с автоматической настройкой некоторых атрибутов - я настроил maven, чтобы поместить номер версии jar, версию 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, так что, вероятно, последующим разработчикам кода будет легче следовать.

Похожие вопросы