简体   繁体   中英

Executable jar won't find the properties files

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.

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>

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.

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.

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">
[....]

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM