Java 可执行 jar 找不到属性文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4126030/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 11:53:34  来源:igfitidea点击:

Executable jar won't find the properties files

javaeclipsejarmaven

提问by

I use this code in my program to load a properties file:

我在我的程序中使用此代码加载属性文件:

Properties properties = new Properties();
URL url = new App().getClass().getResource(PROPERTIES_FILE);
properties.load(url.openStream());

The code runs fine in Eclipse. Then I package the program into a JAR named MyProgram.jar, and run it, I got a NullPointerException at the second line. The JAR doesn't contain the properties file, they both are in the same directory. I am using Maven to create the JAR. How can I fix this problem?

代码在 Eclipse 中运行良好。然后我将程序打包到一个名为 MyProgram.jar 的 JAR 中,并运行它,我在第二行得到一个 NullPointerException。JAR 不包含属性文件,它们都在同一目录中。我正在使用 Maven 创建 JAR。我该如何解决这个问题?

UPDATE: I don't want to add the properties file to the JAR, since it will be created at deployment time.

更新:我不想将属性文件添加到 JAR,因为它将在部署时创建。

采纳答案by Pascal Thivent

BalusC is right, you need to instruct Maven to generate a MANIFEST.MFwith the current directory (.) in the Class-Path:entry.

BalusC 是对的,需要指示 Maven 生成一个MANIFEST.MF带有当前目录 ( .) 的Class-Path:条目。

Assuming you're still using the Maven Assembly Plugin and the jar-with-dependenciesdescriptor to build your executable JAR, you can tell the plugin to do so using the following:

假设您仍在使用 Maven 程序集插件和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>

回答by lscoughlin

EDIT: this is to respond to your comment:

编辑:这是为了回应您的评论:

You need to make sure that the properties file is on the class path with the right root for the java invocation that stars up the jar file. if your path is

您需要确保属性文件位于类路径上,并且具有启动 jar 文件的 java 调用的正确根。如果你的路径是

stuff/things.properties

东西/东西.properties

and the runtime location is

并且运行时位置是

/opt/myapp/etc/stuff/things.properties

/opt/myapp/etc/stuff/things.properties

and the jar file is in

并且jar文件在

/opt/myapp/bin/myjar

/opt/myapp/bin/myjar

then you need to launch as

那么你需要启动

/path/to/java -cp "/opt/myapp/etc:/opt/myapp/bin/myjar.jar" my.pkg.KavaMain

/path/to/java -cp "/opt/myapp/etc:/opt/myapp/bin/myjar.jar" my.pkg.KavaMain

working with this kind of config can be irksome in a dev environment, luckily, there's the maven exec pluginthat will get you the right kind of launch scenario.

在开发环境中使用这种配置可能会令人厌烦,幸运的是,maven exec 插件可以为您提供正确的启动场景。

Original Answer:

原答案:

You want to read about the maven resources plugin.

您想阅读有关Maven 资源插件的信息

Basically you want to add something like this:

基本上你想添加这样的东西:

<plugin>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
                <resources>
                        <resource>
                                <directory>src/main/java</directory>
                                <includes>
                                        <include>**/*properties</include>
                                </includes>
                        </resource>
                </resources>
        </configuration>
<plugin>

to your pom.xml assuming that you're propertis file is with your java sources -- really it should be in src/main/resources.

到您的 pom.xml 假设您的属性文件与您的 java 源代码在一起——实际上它应该在 src/main/resources 中。

回答by BalusC

There are two workarounds:

有两种解决方法

  1. Don't use the JAR as executabele JAR, but as library.

    java -cp .;filename.jar com.example.YourClassWithMain
    
  2. Obtain the root location of the JAR file and get the properties file from it.

    URL root = getClass().getProtectionDomain().getCodeSource().getLocation();
    URL propertiesFile = new URL(root, "filename.properties");
    Properties properties = new Properties();
    properties.load(propertiesFile.openStream());
    
  1. 不要将 JAR 用作可执行文件 JAR,而是用作库。

    java -cp .;filename.jar com.example.YourClassWithMain
    
  2. 获取 JAR 文件的根位置并从中获取属性文件。

    URL root = getClass().getProtectionDomain().getCodeSource().getLocation();
    URL propertiesFile = new URL(root, "filename.properties");
    Properties properties = new Properties();
    properties.load(propertiesFile.openStream());
    

None of both are recommended approaches! The recommend approach is to have the following entry in JAR's /META-INF/MANIFEST.MFfile:

两者都不是推荐的方法!推荐的方法是在 JAR/META-INF/MANIFEST.MF文件中包含以下条目:

Class-Path: .

Then it'll be available as classpath resource the usual way. You'll really have to instruct Maven somehow to generate the MANIFEST.MFfile like that.

然后它将以通常的方式作为类路径资源可用。您真的必须以某种方式指示 Maven 生成这样的MANIFEST.MF文件。

回答by Daniel F. Thornton

I had a similar problem, and this thread was a big help! FYI, I modified my Ant buildfile to do the MANIFEST-making, then designated that manifest when JAR-ing my server-side code:

我有一个类似的问题,这个线程是一个很大的帮助!仅供参考,我修改了我的 Ant 构建文件以进行清单制作,然后在 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">
[....]

回答by Praveen Raj

thanks to all this code work out for me this url get our runnable jar location so easily i have to read my properties file so put your properties file in your runnable jar file location

感谢所有这些代码为我解决了这个 url 获取我们可运行的 jar 位置如此容易我必须读取我的属性文件所以将您的属性文件放在您的可运行 jar 文件位置

URL root = getClass().getProtectionDomain().getCodeSource().getLocation();
URL propertiesFile = new URL(root, "filename.properties");
Properties properties = new Properties();
properties.load(propertiesFile.openStream());