6

I am getting FileNotFoundException while the file is clearly present in the jar. why is it so?

java.io.FileNotFoundException: file:/Users/serviceuser/project/coolApp/target/coolApp-1.0-SNAPSHOT.jar!/BOOT-INF/classes!/ssl_certs/mysslstore.jks (No such file or directory)
    at java.base/java.io.FileInputStream.open0(Native Method) ~[na:na]
    at java.base/java.io.FileInputStream.open(FileInputStream.java:219) ~[na:na]
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:157) ~[na:na]
    at java.base/java.io.FileInputStream.<init>(FileInputStream.java:112) ~[na:na]

However, I see the files packaged in jar.

jar -tf coolApp-1.0-SNAPSHOT.jar | grep ssl

enter image description here

EDIT I load the file as following

new FileInputStream(CoolApp.class.getClassLoader().getResource("ssl_certs/mysslstore.jks").getFile())
catch23
  • 17,519
  • 42
  • 144
  • 217
brain storm
  • 30,124
  • 69
  • 225
  • 393

3 Answers3

10

Here :

new FileInputStream(CoolApp.class.getClassLoader().getResource("ssl_certs/mysslstore.jks").getFile());

getFile() is invoked on a URL included in a jar.
As a result, it provides a particular File object since that is not a File directly accessible in the filesystem.

And the URL javadoc confirms that (emphasis is mine) :

Class URL represents a Uniform Resource Locator, a pointer to a "resource" on the World Wide Web. A resource can be something as simple as a file or a directory, or it can be a reference to a more complicated object, such as a query to a database or to a search engine.

So the FileInputStream(File) constructor cannot necessarily be able to open that "special" file :

A FileInputStream obtains input bytes from a file in a file system. What files are available depends on the host environment.

You can compare what you try to do with the following :

new FileInputStream("/Users/serviceuser/project/coolApp/target/coolApp-1.0-SNAPSHOT.jar!/BOOT-INF/classes!/ssl_certs/mysslstore.jks")

As you guessed, the file included in the jar(mysslstore.jks) could not be resolved by the OS filesystem.

Instead of, use getResourceAsStream() that returns an input stream. That input stream refers to the bytes sequence represented by the resource. In this way, the client code doesn't depend any longer on the way which the resource is stored.

InputStream is = CoolApp.class.getClassLoader().getResourceAsStream("ssl_certs/mysslstore.jks"));
davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • makes sense. Accepted the answer although yet to test it. – brain storm Aug 12 '19 at 21:19
  • 1
    `getResourceAsStream()` is the key and it has been forgot so many times for people. – LHCHIN Aug 13 '19 at 01:25
  • There is no constructor for new FileInputStream() that takes InputStream. There is no need to wrap `.getResourceAsStream` with FileInputStream. just `CoolApp.class.getClassLoader().getResourceAsStream("ssl_certs/mysslstore.jks")` is sufficient – brain storm Aug 15 '19 at 17:31
  • @brain storm In fact it would make no sense at all :) Thanks I fixed the last line. – davidxxx Aug 17 '19 at 07:36
  • In this case, CoolApp would be the name of the main class of the Spring project...right? – José Ripoll Nov 11 '19 at 21:01
0
I was facing the same issue in spring boot and I have tried many things like bellow but nun of them is working. thease all are working locally but  It is giving FileNotFoundException in dev environmnet because when we build a JAR, the resources get placed into the root directory of the packaged artifacts and our downloaded files I placed inside resource folder. 

Method 1: Working solution for jars
InputStream stram=getClass().getClassLoader().getResourceAsStream(File.separator+"database.properties");
URL url = getClass().getClassLoader().getResource(File.separator+"database.properties");

Only thing which worked is ResourceLoader. Need to Autowire it:
    @Autowired
    ResourceLoader resourceLoader;

        Resource resource = resourceLoader.getResource("classpath:" + File.separatorChar + NPIConstants.VAR_FOLDER
                + File.separatorChar + NPIConstants.TPSPIDsBUCKET_FILENAME);
        InputStreamResource isResource = new InputStreamResource(resource.getInputStream());

Method 1: Not Working solution for jars
ClassLoader loader = Thread.currentThread().getContextClassLoader();
InputStream is = loader.getResourceAsStream("database.properties");
System.out.println(is.available());

Method 2:  Not Working solution for jars
Resource resource = new ClassPathResource("database.properties");
InputStream input = resource.getInputStream();

Method 3: Not Working solution for jars
File file = new File("resources/database.properties");
String absolutePath = file.getAbsolutePath();

Method 4: Not Working solution for jars
File file = new File(getClass().getClassLoader().getResource("database.properties").getFile());

Method 5: Not Working solution for jars
ClassLoader classLoader = getClass().getClassLoader();
classLoader.getResource("database.properties");
String path  = classLoader.getResource("database.properties").getPath();
alok
  • 2,718
  • 21
  • 17
-2

Files like this need to be in the resources directory.

Daisy Day
  • 652
  • 7
  • 19