Stephane
Stephane

Reputation: 12750

Read a file in the jar

I'm trying to open a file sitting in my jar archive.

I use this Maven plugin:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.fatec.migration.script.utils.Script</mainClass>
        </manifest>
      </archive>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
    <executions>
      <execution>
        <id>assemble-all</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

I build and then copy my archive:

cp /home/stephane/dev/java/projects/fatec/Fiabilisation_Controles_XP_AS/target/fatec-script-jar-with-dependencies.jar .

Now I can try running it:

java -jar fatec-script-jar-with-dependencies.jar 1 2017-02-01 2017-02-02 all

Alas, it cannot find the file:

The file secure/extrapack-renew.sql could not be opened.
java.lang.NullPointerException
    at com.fatec.migration.script.utils.AbstractScript.loadSqlStatement(AbstractScript.java:75)

But the file does exist, I can see it in the archive:

$ jar -tvf target/fatec-script-jar-with-dependencies.jar | grep "secure/extrapack-renew.sql"
  1844 Fri Feb 10 17:43:46 CET 2017 secure/extrapack-renew.sql

Here is how I try opening the file:

protected String loadSqlStatement(String scriptPath, String filename) {
    String filepath = buildSqlFilePath(scriptPath, filename);
    try {
        return new String(Files.readAllBytes(Paths.get(getClass().getResource(filepath).toURI())));
    } catch (Exception e) {
        System.err.println("The file " + filepath + " could not be opened.");
        e.printStackTrace();
    }
    return null;
}

private String buildSqlFilePath(String scriptPath, String filename) {
    return scriptPath + "/" + filename;
}    

The scriptPath is "secure" and the filename is "extrapack-renew.sql".

What am I missing ?

Upvotes: 3

Views: 301

Answers (2)

Stephane
Stephane

Reputation: 12750

My solution was to have the properties files NOT in the jar archive, contrary to what was asked in the original title of the question.

I got it working, with a properties file sitting in the project home directory.

$ ll
total 52K
-rw-rw-r-- 1 stephane   10 févr. 13 10:49 application.properties
-rw-r--r-- 1 stephane 6,1K févr. 10 17:22 pom.xml

I can open this file and load its properties with:

properties.load(new FileInputStream(new File(DB_AUTOSELF_PROPERTIES_FILENAME)));

Then I can move the .jar archive and the properties file to another directory, and run the application:

$ pwd
/home/stephane/trash
$ cp ~/dev/java/projects/AS/target/script-jar-with-dependencies.jar .
$ cp ~/dev/java/projects/AS/application.properties .
$ vi application.properties 
-rw-rw-r-- 1 stephane 10 févr. 13 10:53 application.properties
java -jar script-jar-with-dependencies.jar 1 2016-12-01 2017-02-12 all

My pom.xml file contains the plugins to copy the resources and create a fat jar archive:

  <plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <executions>
      <execution>
        <id>copy-resources</id>
        <phase>validate</phase>
        <goals>
          <goal>copy-resources</goal>
        </goals>
        <configuration>
          <outputDirectory>${basedir}/target</outputDirectory>
          <resources>
            <resource>
              <directory>src/main/resources</directory>
              <filtering>true</filtering>
            </resource>
          </resources>
        </configuration>
      </execution>
    </executions>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>3.0.0</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.fatec.migration.script.utils.Script</mainClass>
        </manifest>
      </archive>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
    <executions>
      <execution>
        <id>assemble-all</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>

Upvotes: 0

davidxxx
davidxxx

Reputation: 131316

I think that your problem is the way you use getResource() :

Paths.get(getClass().getResource(filepath).toURI());

You use a relative classpath (that is relative to the the current class location) to retrieve the "extrapack-renew.sql" file.
It means that this resource has to be located inside this path in your jar to be retrieved.

If the resource is not located inside the current class path, the path used to retrieve the resource should start with a "/" character in order to specify an absolute name of the resource:

Paths.get(getClass().getResource("/"+filepath).toURI());

Of course if you use maven, extrapack-renew.sql should be in

the src/main/resources/secure folder of the source project so that "/secure/extrapack-renew.sql" be a resource in the classpath.

Upvotes: 1

Related Questions