Executable jar won't find the properties files

45,205

Solution 1

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>

Solution 2

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.

Solution 3

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.

Share:
45,205
Admin
Author by

Admin

Updated on February 03, 2020

Comments

  • Admin
    Admin over 4 years

    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.

  • Admin
    Admin over 13 years
    Thanks, but I don't want to add the properties file to the JAR. It will be changed at deployment time.
  • BalusC
    BalusC over 13 years
    As per your edit: the -cp argument is ignored when using -jar argument. It has really to go in MANIFEST.MF file :)
  • Admin
    Admin over 13 years
    Oops I tried the first option before but I used . COMMA filename.jar. Maybe that's why it didn't work. Thanks for your help.
  • Devanshu Mevada
    Devanshu Mevada over 13 years
    If you're not using the maven assembly plugin, let me know and I'll update my answer.
  • Admin
    Admin over 13 years
    With the executions section, I don't have to run mvn assembly:assembly separately right? By the way, thanks for answering all my questions on Maven.
  • Devanshu Mevada
    Devanshu Mevada over 13 years
    @HaiMinhNguyen: Indeed, the above execution binds the single goal on the package phase. As a result, running mvn package does create the assembly. Oh, and you're welcome.
  • BalusC
    BalusC over 13 years
    Yes, this is the approach you should take, Hai Minh Nguyen.
  • Bastien Jansen
    Bastien Jansen over 12 years
    Hello, I tried using the above method to create a jar-with-depencies that could load a properties file located in the same directory but it does not work. I run my jar using "java -jar myjar.jar". I tried retrieving the properties file using both Class.getResource() Class.ClassLoader.getResource(), with and without a leading slash in the file name, but none of these work. If i println the content of java.class.path, I only get my jar file (no ".", though it is correctly set in the MANIFEST's Class-Path). Could someone help me please?
  • lscoughlin
    lscoughlin about 12 years
    @BalusC righto, fixed up. Can't go in the MANIFEST.MF if it could move at runtime.
  • matbrgz
    matbrgz over 11 years
    There's one reason for avoiding the Classpath - namely if the content changes between reads. The resource loader caches the first content
  • jgreen
    jgreen over 8 years
    This thread was helpful to me. In my case (non-maven project), I also had to make the path of the resource I was requesting (which was buried in my src tree) absolute by prefacing it with a "/" (linux).