Reading files in resource path from jar artifact

Jonathan Henrique
2 min readMay 2, 2018

--

I recently had to read some files from the resources folder in a spring + kotlin project, during the development period I did not encounter any problems, my headache started after the artifact was wrapped …

In debug mode, you can read the file using this:

import java.nio.file.Files/**
* Created by: jonathan
* DateTime: 2018-05-02 10:38
**/
@Configuration
class InDebugMode(final val loader: ResourceLoader)
{
init
{
val file = loader.getResource("classpath:/example.txt").file
Files.lines(file.toPath()).forEach { println(it) }
}
}

Output:

line 1
line 2
line 3
...

We could use these lines for anything.
Great, no? NOPE!

See what happens when I run the application from jar file:

ERROR 7526 ---[main] o.s.boot.SpringApplication: Application run failedorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'inDebugMode' defined in URL [jar:file:/home/user/work/demo-app/target/demo-app.jar!/BOOT-INF/classes!/org/ixfun/demo/get/file/InDebugMode.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate 
[org.ixfun.demo.get.file.InDebugMode$$EnhancerBySpringCGLIB$$88d0d6eb]: Constructor threw exception; nested exception is java.io.FileNotFoundException: class path resource [example.txt] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/home/user/work/demo-app/target/demo-app.jar!/BOOT-INF/classes!/example.txt

Cool…

The most interesting is this structure [ /home/user/work/demo-app/target/demo-app.jar!/BOOT-INF/classes!/example.txt ] exists !

The big problem is the method of consuming the files.
The spring context is not contained within the method and the application try to use the absolute path to build a file by ( Files interface)… and fail :|

I can read the files using the good and old InputStream and BufferedReader :

package org.ixfun.demo.get.file

import org.springframework.context.annotation.Configuration
import org.springframework.context.support.ClassPathXmlApplicationContext
import java.io.BufferedReader
import java.io.InputStreamReader

/**
* Created by: jonathan
* DateTime: 2018-05-02 10:38
**/
@Configuration

class InJarMode
{
private val appContext = ClassPathXmlApplicationContext()
init
{
val file = appContext.getResource("classpath:/example.txt")
if (file.isReadable)
{
val im = file.inputStream
val br = BufferedReader(InputStreamReader(im))
br.lines().forEach { println(it) }
br.close()
}
}
}

This way the solution works in both cases.

--

--