Cannot read Resource from /static folder in Spring Boot - java

Given a Spring Boot Maven Project with this structure:
src
main
resources
static
file.txt
This gets packaged into a jar file:
static
file.txt
I have tried the following ways to try to read file.txt:
File file = ResourceUtils.getFile("file.txt");
File file = ResourceUtils.getFile("/file.txt");
File file = ResourceUtils.getFile("static/file.txt");
File file = ResourceUtils.getFile("/static/file.txt");
None of these work.

It's a resource. Packaged inside a jar file. A File represents a path on the file system. So it can't represent an entry of a jar file.
Use MyClass.class.getResourceAsStream("/static/file.txt"). That uses the class loader, and thus loads resources from all the directories and jar files in the classpath.

Related

How to read current project path in .properties file

I have abc.jks file under resources folder and i need to read that abc.jks file in test.properties file. How to read abc.jks file in test.properties file.
In application.properties (or how you name it) assuming you use maven and you execute your spring application in the default project you can refer to the file like:
my.file.name = ./src/main/resources/abs.jks
or if this is for test purpose only you can put in the test resources and refer like this:
my.file.name = ./src/test/resources/abs.jks
For me the best is to not be dependent on folder and always use classloader resource, but if you have to refer a path on the filesystem, from java code you can do this:
URL url = getClass().getClassLoader().getResource("abs.jks");
File file = Paths.get(url.toURI()).toFile().getAbsolutePath();

Java classloader not able to find resource in jar file

I have a runnable jar file which is not able to access my resources which reside outside of the default src directory. Based on my understanding from What is the difference between Class.getResource() and ClassLoader.getResource(), I should be able to access root/res/img/img1.png (see folder setup below) by using the following getResourceFile function:
public class Foo {
private static final ClassLoader CLASS_LOADER = Foo.class.getClassLoader();
public static File getResourceFile(String relativePath) {
// Since I'm using getClassLoader, the path will resolve starting from
// the root of the classpath and it'll take an absolute resource name
// usage: getResourceFile("img/img1.png")
// result: Exception in thread "main" java.lang.NullPointerException
return new File(CLASS_LOADER.getResource(relativePath).getFile());
}
}
folder setup:
root/
src/
foo/
bar/
res/
img/
img1.png
audio/
audio1.wav
The problem arises when I try to execute the jar executable itself. However, the strange thing is that I was not able to replicate this through eclipse IDE which was actually able to resolve the path correctly. I have added the resource directory to the build path via (Project -> Properties -> Java Build Path -> Add Folder) so Java should be able to find the resource folder at runtime.
Is there something I'm missing in terms of generating the jar file? When unpacking the jar file everything seems to be in order with the img and audio directories being in the root (given the above initial folder setup):
foo/
/bar
img/
img1.png
audio/
audio1.wav
Files can only be used to represent actual files in your filesystem. And once you package your files into a JAR, the resource (img/img1.png) is not a file anymore, but an entry in the JAR file. As long as you use the folder structure from within Eclipse, the resources are individual files so everything is fine.
Try this:
System.out.println(CLASS_LOADER.getResource(relativePath));
It will print a URL, but it will not be a valid path to a file in your file system, but to an entry within the JAR file.
Usually, you will only want to read a resource. In that case, use getResourceAsStream() to open an InputStream.

How to create a single jar to include multiple java files from different folder

How my project structure looks like
|---> src (folder)
|----> Repository (folder)
|----> util (folder)
|----> config (folder)
|---> Repository (folder)
|---> property file 1
|---> property file 2
|---> property file 3
Config folder has the same structure as Repository folder.
Util folder structure is
|---> util (folder)
|---> Main class file
|---> Sub main class file
|---> common function file
|---> Report file
Now my Main class file under util folder in the default file which fetches the data from the files under Repository and config folder. It also has a link which opens the Sub main class file and uses the common function as well as Report file under the util folder itself.
I am successfully able to run the code from Eclipse but now I need to create a jar file to perform these actions. I tried to create a jar file from command prompt as well as from Eclipse, it opens the Main class file UI but unable to fetches the data from other folder files or unable to open the sub main class file.
I am pretty new to this jar thing and don't know much about it.
Suggestions ?
You can use the following command to build the jar and specify the main class entry point (Main).
jar cfe output.jar Main src/Repository/* src/util/*.class
you can write multiple files when creating the jar
jar cf Output.jar src/util/Main.class src/util/SubMain.class src/Repository/*
EDIT as per the updated requirements in comments
With this method, you'll just create a jar. Note that it is different from an executable jar. To create a executable jar, you have to specify the main class that you want to be executed when this jar will be clicked upon.
To specify that file, you've to create a MANIFEST.MF
create a file named MANIFEST.MF and put it in META-INF folder and include it while creating the jar in command line
META-INF/MANIFEST.MF
Manifest-Version: 1.0
Main-Class: com.path.to.MainClass
When you package files in a jar they are no longer files. They become streams/blobs. Make sure you are not loading any property files as File in your code. Use below code to load property files.
InputStream inputStreamObject = getClass().getResourceAsStream(file_name);
BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputStreamObject, "UTF-8"));
StringBuilder responseStrBuilder = new StringBuilder();
String inputStr;
while ((inputStr = streamReader.readLine()) != null)
responseStrBuilder.append(inputStr);

Reading a resource in a war file which is not under classes dir

I am having a web application having following structure:
WEB-INF
|-classes
-- This is empty
|-templates
|-abc.properties
|- xyz.properties
|-lib
|-internal.jar (all classes of our application)
|- other jars
These are bundled as a war
I want to read properties in the the files present in WEB-INF/templates.
NOTE: Above operation needs to be done from one of the class present in internal.jar. Basically they are on classpath
I tried following to get the resources but it is not able to search it.
{code}
1.
final InputStream inputStream = FileTemplateDaoImpl.class.getClassLoader().getResourceAsStream(resourcePath)
{/code}
where i tried following as resource path:
templates/abc.properties
/WEB-INF/templates/abc.properties
I presume here that once you open the war file these *.properties files are available under WEB-INF/templates, now the class which is trying to utilize these property files, try below mentioned code block.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
InputStream is = classLoader.getResourceAsStream("WEB-INF/templates/abc.properties");

Java - Classpath issue

I have a products.jar file. Inside that there is one class com.ClassA. The structure of the project is like
products
|--test
|--com
|--ClassA.java
|--dependencies
|---inputs.txt
Inside eclipse, ClassA.java is accessing the inputs.txt file by the following path and it is working fine
private static final String PROPERTIES_FILE_PATH = "test/dependencies/inputs.txt";
test package is in the java build path -> sources
But when I am exporting this project as products.jar, I find that in the jar file there is no test directory. There are two dirs com and dependencies at the root of the jar file. So when I am trying to execute the ClassA (residing in jar file) through command line, I am getting the following exception:
JUnit version 4.8.2
java.io.FileNotFoundException: test/dependencies/inputs.txt (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:137)
at java.io.FileInputStream.<init>(FileInputStream.java:96)
So after finding that test dir is not being exported in jar file, I changed the path of the file in my ClassA.java to dependencies/inputs.txt. It didn't work in eclipse but I thought that it would work in jar because jar file is in classpath and dependencies folder is at the root of the jar file so the java launcher will be able to locate the dependencies folder and then inputs.txt file.
But unfortunately it is also not working.
You can't use FileInputStream to read a file packed inside a JAR - it's not a file any more. FileInputStream only works for actual disk files.
You need to read the resource using Class.getResourceAsStream (javadoc), e.g.
InputStream stream = getClass().getResourceAsStream("/dependencies/inputs.txt");
You leave off the test prefix because it's not in the JAR file structure.
FileInputStream() will not read inside your jar, only files on the file system. Use .getClass().getResourceAsStream(resourcename) or .getClass().getClassLoader().getResourceAsStream(resourcename)
More info on the javadocs for class getResourceAsStream and classloader getResourceAsStream()

Categories