G-M
G-M

Reputation: 346

Classloader and FileInputStream won't find file inside JAR

I'm building my jar-file with maven, they include all dependencies, so i can run the jars via

java -jar

Inside the jar I have a config.json which is the the app-configuration. I verified that config.json is really inside the jar:

/> jar tf cloudimport-0.1-jar-with-dependencies.jar | grep config.json
config.json

But when I run the application it won't find the config.json:

ClassLoader classLoader = getClass().getClassLoader();
System.out.println(classLoader.getResource("config.json"));
File configFile =  new File(classLoader.getResource(fileName).getFile());
(Exception thrown here ->) FileReader fileReader = new FileReader(configFile);
BufferedReader br = new BufferedReader(fileReader);

produces:

java -jar cloudimport-0.1-jar-with-dependencies.jar
jar:file:/home/ubuntu/cloudimport-0.1-jar-with-dependencies.jar!/config.json
java.io.FileNotFoundException: file:/home/ubuntu/cloudimport-0.1-jar-with-dependencies.jar!/config.json (No such file or directory)

The Class that runs the above code is located in the jar at:

com.test.cloudsync.config.AppConfig.class

If I run the app from intelliJ in windows, it works properly, but execution from intelliJ means that the Main Class is executed not the jar.

I have already searched for this but answers like: What is the difference between Class.getResource() and ClassLoader.getResource()?

didn't help...

jar-contents

// EDIT The suggestion was that the Excpetion wasn't throwed by the ClassLoader - this is true. I removed some stuff so I could limit the scope, now it seems like the problem is that I try to open a FileINputStream but this is not possible I guess if the file is withing a jar?

The Full Stack Trace:

/> java -jar java_cloudsync/com/tsg/cloudimport/cloudimport/0.1/cloudimport-0.1-jar-with-dependencies.jar   
jar:file:/home/ubuntu/java_cloudsync/com/tsg/cloudimport/cloudimport/0.1/cloudimport-0.1-jar-with-dependencies.jar!/config.json
    java.io.FileNotFoundException: file:/home/ubuntu/java_cloudsync/com/tsg/cloudimport/cloudimport/0.1/cloudimport-0.1-jar-with-dependencies.jar!/config.json (No such file or directory)
            at java.io.FileInputStream.open0(Native Method)
            at java.io.FileInputStream.open(FileInputStream.java:195)
            at java.io.FileInputStream.<init>(FileInputStream.java:138)
            at java.io.FileReader.<init>(FileReader.java:72)
            at com.tsg.cloudsync.config.AppConfig.readConfigFile(AppConfig.java:33)
            at com.tsg.cloudsync.config.AppConfig.<init>(AppConfig.java:23)
            at com.tsg.cloudsync.awsutils.SQSSocket.<init>(SQSSocket.java:34)
            at com.tsg.cloudsync.awsutils.SQSSocket.<clinit>(SQSSocket.java:19)
            at com.tsg.cloudsync.NewFileWatchDog.main(NewFileWatchDog.java:24)
    Exception in thread "main" java.lang.ExceptionInInitializerError
            at com.tsg.cloudsync.NewFileWatchDog.main(NewFileWatchDog.java:24)
    Caused by: java.lang.NullPointerException
            at com.tsg.cloudsync.config.AppConfig.getAWSCredentials(AppConfig.java:50)
            at com.tsg.cloudsync.awsutils.SQSSocket.<init>(SQSSocket.java:35)
            at com.tsg.cloudsync.awsutils.SQSSocket.<clinit>(SQSSocket.java:19)
            ... 1 more

Upvotes: 2

Views: 2822

Answers (2)

G-M
G-M

Reputation: 346

So it turned out that I was trying to define a

ClassLoader classLoader = getClass().getClassLoader();
File f = new File(classLoader.getResource(fileName).getFile())
FileReader fileReader = new FileReader(configFile);
BufferedReader br = new BufferedReader(fileReader);

Which is not possible, since the jar itself is a File. So instead to get the Contents of a file do:

ClassLoader classLoader = getClass().getClassLoader();
InputStream in = classLoader.getResourceAsStream(fileName);
BufferedReader br = new BufferedReader(new InputStreamReader(in));

Also refer to here: Reading a resource file from within jar

Notice the difference getResourceAsStream(fileName) and getResource(fileName).getFile()

Thanks for pointing me to the right direction!

Upvotes: 1

SubOptimal
SubOptimal

Reputation: 22973

Assume following simple structure

bin/
src/AppConfig.java
src/config.json
src/manifest.mf

AppConfig.java

package com.test.cloudsync;
public class AppConfig {
    void check() {
        ClassLoader classLoader = getClass().getClassLoader();
        System.out.println(classLoader.getResource("config.json"));
    }
    public static void main(String[] args) {
        new AppConfig().check();
    }
}

manifest.mf

Main-Class: com.test.cloudsync.AppConfig

compile and build the Jar file

javac -d bin/ src/*.java
cp src/config.json bin/config.json
jar cfm test.jar src/manifest.mf -C bin/ .

run the Jar

java -jar test.jar

output

jar:file:/tmp/foobar/test.jar!/config.json

This demonstrates that the exception is not raised by the line ClassLoader classLoader = getClass().getClassLoader()

Upvotes: 0

Related Questions