Исполняемая банка не найдет файлы свойств
Я использую этот код в своей программе для загрузки файла свойств:
Properties properties = new Properties();
URL url = new App().getClass().getResource(PROPERTIES_FILE);
properties.load(url.openStream());
Код отлично работает в Eclipse. Затем я упаковываю программу в JAR с именем MyProgram.jar и запускаю ее, я получил исключение NullPointerException во второй строке. JAR не содержит файл свойств, они оба находятся в одном каталоге. Я использую Maven для создания JAR. Как я могу исправить эту проблему?
UPDATE: я не хочу добавлять файл свойств в JAR, так как он будет создан во время развертывания.
Ответы
Ответ 1
BalusC прав, вам нужно указать Maven для создания MANIFEST.MF
с текущим каталогом (.
) в записи Class-Path:
.
Предполагая, что вы все еще используете Maven Assembly Plugin и дескриптор jar-with-dependencies
для создания исполняемого JAR, вы можете сказать плагину сделать это, используя следующее:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.stackoverflow.App</mainClass>
</manifest>
<manifestEntries>
<Class-Path>.</Class-Path> <!-- HERE IS THE IMPORTANT BIT -->
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- append to the packaging phase. -->
<goals>
<goal>single</goal> <!-- goals == mojos -->
</goals>
</execution>
</executions>
</plugin>
Ответ 2
Есть два обходных решения:
-
Не используйте JAR как executabele JAR, а как библиотеку.
java -cp .;filename.jar com.example.YourClassWithMain
-
Получить корневое расположение файла JAR и получить из него файл свойств.
URL root = getClass().getProtectionDomain().getCodeSource().getLocation();
URL propertiesFile = new URL(root, "filename.properties");
Properties properties = new Properties();
properties.load(propertiesFile.openStream());
Ни один из них не рекомендуется! Рекомендуемый подход состоит в следующем: запись в файле JAR /META-INF/MANIFEST.MF
:
Class-Path: .
Затем он будет доступен как ресурс пути к классам обычным способом. Вам действительно нужно будет как-то указать Maven для создания файла MANIFEST.MF
.
Ответ 3
EDIT: это ответ на ваш комментарий:
Вам нужно убедиться, что файл свойств находится в пути класса с правильным корнем для вызова java, который запускает файл jar. если ваш путь
stuff/things.properties
и время выполнения
/opt/myapp/etc/stuff/things.properties
а файл jar находится в
/opt/myapp/bin/myjar
то вам нужно запустить как
/path/to/java -cp "/opt/myapp/etc:/opt/myapp/bin/myjar.jar" my.pkg.KavaMain
работа с подобным конфигом может быть неприятной в среде dev, к счастью, там maven exec plugin, который доставит вам правильный вид сценария запуска.
Оригинальный ответ:
Вы хотите прочитать плагин ресурсов maven.
В основном вы хотите добавить что-то вроде этого:
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*properties</include>
</includes>
</resource>
</resources>
</configuration>
<plugin>
к вашему pom.xml, предполагая, что вы файл propertis с вашими источниками java - действительно, он должен быть в src/main/resources.
Ответ 4
У меня была аналогичная проблема, и эта тема была большой помощью! FYI, я модифицировал свой файл Ant buildfile для выполнения MANIFEST-создания, а затем обозначил этот манифест, когда JAR-код моей серверной части:
<!-- Create a custom MANIFEST.MF file, setting the classpath. -->
<delete file="${project.base.dir}/resources/MANIFEST.MF" failonerror="false"/>
<manifest file="${project.base.dir}/resources/MANIFEST.MF">
<attribute name="Class-Path" value="." />
</manifest>
<!-- JAR the server-side code, using the custom manifest from above. -->
<jar destfile="services/${name}.aar" manifest="${project.base.dir}/resources/MANIFEST.MF">
[....]