Есть ли способ определить постоянное значение 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 для его обработки?