可执行 jar 找不到属性文件

发布于 2024-10-01 16:52:42 字数 377 浏览 0 评论 0原文

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

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

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

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

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?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

不忘初心 2024-10-08 16:52:42

BalusC 是对的,您需要指示 Maven 在 Class-Path: 条目中生成一个包含当前目录(.)的 MANIFEST.MF

假设您仍在使用 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>

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

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

  <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>
剩余の解释 2024-10-08 16:52:42

有两种解决方法

  1. 不要将 JAR 用作可执行 JAR,而是用作库。

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

    URL root = getClass().getProtectionDomain().getCodeSource().getLocation();
    URLpropertiesFile = new URL(root, "文件名.properties");
    属性属性 = new Properties();
    属性.load(propertiesFile.openStream());
    

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

Class-Path: .

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

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());
    

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

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.MF file like that.

小矜持 2024-10-08 16:52:42

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

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

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

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

原始答案:

您想阅读maven 资源插件< /a>.

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

<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 假设你的属性文件与你的 java 源文件一起 - 实际上它应该在 src/main/resources 中。

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

stuff/things.properties

and the runtime location is

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

and the jar file is in

/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

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

Original Answer:

You want to read about the maven resources plugin.

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.

逆流 2024-10-08 16:52:42

我也遇到了类似的问题,这个帖子给了我很大的帮助!仅供参考,我修改了 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">
[....]

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:

<!-- 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">
[....]
耀眼的星火 2024-10-08 16:52:42

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

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

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 root = getClass().getProtectionDomain().getCodeSource().getLocation();
URL propertiesFile = new URL(root, "filename.properties");
Properties properties = new Properties();
properties.load(propertiesFile.openStream());
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文