Reading a resource file in Jar - java

I am using IntelliJ Idea and trying to read a json file from the resources folder in the project structure. I read the json file and return the contents using jackson.
return mapper.readValue(File("src/main/resources/file.json"), Map::class.java)
As soon i build the project and make a jar it throws me an error it cannot find the file. I looked here a bit and found that i should use ClassLoader to read files from the resources folder. So i do this now -
mapper.readValue(File( ClassLoader.getSystemClassLoader().getResource("src/main/resources/file.json").toURI()), Map::class.java)
Now I get a NullPointerException. I am a bit lost now. Any help is deeply appreciated.

Assuming your build follows the default convention, whatever under src/main/resource will be available on the root of the classpath, so you just need to change the code to:
mapper.readValue(ClassLoader.getSystemClassLoader().getResourceAsStream("file.json"), Map::class.java)

Related

How to read an internal file in a web project

All, Forgive me I am still learning the Java development right row.
Say we have the structure of web project like below.
The src and config is under the Java Resources folder of web project.
src
...
|- a.b.c.package
|-test.java
...
config
|-1.xml
|-2.xml
...
configfolder
|-1.properties
|-2.properties
testfolder
|-test.properties
I want to know if I use the dom4j. How to read the xml file(1.xml) within the test.java. Thanks.
My Experiment
In the test.java. I found I can succeed to use the class.getClassLoader().getResourceAsStream("test.properties") to load test.properties in any folders or sub folder of src.
Does it mean getResourceAsStream can search the specified file in any of the folders of project recursively? I just can't understand it how it works. Thanks.
getResourceAsStream() method searches for resources with classpath as root. I suppose in your case 'testfolder' is source folder. I you would have your 1.properties in 'testfolder/mypath/1.properties' then you need to specify getResourceAsStream("mypath/1.properties")

Why does getResource return null

I'm trying to access a file in my project. But getResource method returns null.
This is how my project looks like:
Thread.currentThread().getContextClassLoader().getResource("assets/xxx.png"); //returns null
And how project folder in eclipse workspace looks like:
Why? I want to access files in my assets folder?
Edit
I created a jar file and this is content of the jar:
Solved
First of all, I've a lot of image files so I want to organize all them in a folder. I put the assets folder in src directory and finally I was able to access the files.
this.getClass().getClassLoader().getResource("assets/xxx.png");
There are lot of ways to add a resource to the jar file, you can put it in src, add as a resource if you use maven, ant etc... If you able to bundle whole directory then you should be able to use your original piece of code.
With the current structure you can use following piece of code.
Thread.currentThread().getContextClassLoader().getResource("/xxx.png").
Try using / prefixing.
Thread.currentThread().getContextClassLoader().getResourceAsStream("/xxx.png")
For someone struggling as me. For Maven just run mvn clean install.
After that Thread.currentThread().getContextClassLoader().getResource() should work.
Is there a reason you're using the the class loader of the current class? Something like this.getClass().getClassLoader().getResource("/xxx.png") should be more reliable.
Use the following code, it should work.
YOUR_CLASS_HERE.class.getClass().getResource( "/xxx.png" );
e.g.
Signin.class.getClass().getResource( "/xxx.png" );
Either Approach will work. its just Filepath issue.
Your Jar Structure shows no "asset" Folder
xxx.png file is directly in Jar File.
Try to remove "assets" from below line of code.
Thread.currentThread().getContextClassLoader().getResource("assets/xxx.png"); //returns null
Also, if you want to use "assets" folder in ur classpath, please ensure that your jar contains "assets" folder.

getting null pointer when reading the properties file

when reading the properties file, iam getting nullpointer exception.
faceConfig.load(ReadPropertyFile.class.getClassLoader().getResourceAsStream("/resources/faces.properties"));
below is the path of properties file facedetections/src/main/resources/faces.properties
i tried in different combinations as my class file that reads in below path /facedetections/src/main/java/com/facial/facedetection/utils/ReadPropertyFile.java
combinations are ../../../../../resource/faces.properties , /resource/faces.properties and
../../../resource/faces.properties
Please suggest what is the correct path i can provide for this.
Edit :
I extracted the war file and providing its path below.
looks your property file under class folder not in resource.
as your screen shot cant find resource folder under class folder.
So just use
ReadPropertyFile.class.getClassLoader().getResourceAsStream("faces.properties")
The path is relative to the point where the object (.class) files are located. Are you sure you have configured your build/test tool to copy the resource file into that structure? Exactly where? That's what counts, not the position of the sources.
Additionally, my understanding is that getResourceAsStream() of most ClassLoaders do not support .. notation.
The position where your resource file is currently located is out of reach of the ClassLoader. If you move your file to /facedetections/src/main/java/resources/faces.properties, then you will be able to use the current code
getResourceAsStream("resources/faces.properties")
I'm making assumptions about your environment. In particular, this is entirely dependent on classloaders. If this doesn't help, please provide object file location, not sources (unless it is the same, but state it).
Since it is unlikely that you get a NPE when the file is not found I assume that faceConfig is null when you execute that line.

Why does getResourceAsStream() work in the IDE but not the JAR?

I just want to read a file into my program. The file is located one directory above the working directory at "../f.fsh". So the following code runs correctly when I run it in the IDE
String name="../f.fsh";
InputStream is = getClass().getResourceAsStream(name);
InputStreamReader isreader=new InputStreamReader(is);//CRASHES HERE WITH NULL POINTER EXCEPTION
BufferedReader br = new BufferedReader(isreader);
but when I create a JAR file that has f.fsh zipped inside of it and run it, it crashes when creating the InputStreamReader, because the InputStream is null.
I've read a bunch of answers to questions about input streams and JAR files, and what I got out of it is that I should be using relative paths, but I am already doing that. From what I understand getResourceAsStream() can find files relative to the root of the project, that is what I want. Why does it not work in the JAR? What is going wrong, how can I fix it?
Does it have to do with the classpath? I thought that was only for including files external to the jar being run.
I have also tried, but still fail, when putting a slash in:
InputStream is = getClass().getResourceAsStream("\\"+name);
I looked at: How to get a path to a resource in a Java JAR file andfound that contents of a JAR may not necesarily be accesible as a file. So I tried it with copying the file relative to the jar (one directory up from the jar), and that still fails. In any case I'd like to leave my files in the jar and be able to read them there. I don't know what's going wrong.
You can't use .. with Class.getResourceAsStream().
To load a resource f.fsh in the same package as the class, use SomeClass.class.getResourceAsStream("f.fsh")
To load a resource f.fsh in a sub-package foo.bar of the package of the class, use SomeClass.class.getResourceAsStream("foo/bar/f.fsh")
To load a resource f.fsh in any package com.company.foo.bar, use SomeClass.class.getResourceAsStream("/com/company/foo/bar/f.fsh")
This is described in the javadoc of the getResource() method, although it lacks examples.
If .. works in Class.getResourceAsStream() while running from Eclipse, it's a bug in Eclipse. Eclipse and other IDEs implement custom class loaders to fetch resources from the project at runtime. It looks like the class loader implementation in Eclipse isn't performing all the necessary validations on input to getResourceAsStream() method. In this case the bug is in your favor, but you will still need to rethink how you structure your resources for your code to work in all cases.
it's mandatory that the name of the file is CASE SENSITIVE
it's mandatory to refresh (F5) the project explorer if the file is moved or copied outside Exclipse

ClassLoader loading the wrong instance of a file

So I see there has already been a post very similar to this issue, however I am in a situation where I have no power to specify the location of this file within my jar and so am hoping someone is aware of a solution to get around this.
So I currently use the following snippet to obtain a file as an input stream, the file 'plugin.xml' is located at the root of the jar and I cannot change this location as another piece of software (dynatrace) creates this file and determines its location.
the standard snippet:
InputStream is = JmxPlugin.class.getResourceAsStream("/plugin.xml");
Now I am aware that the issue is that the ClassLoader is picking up the first file which matches the name 'Plugin.xml' along the classpath (one which isn't in my jar, yay).
Can anyone think of a way to ensure I pick up the correct file without having to move it? The relative path of my class in the jar is com/something/jmx/JmxPlugin.class.
(Id rather not have to unpack the jar in memory).
Many thanks for any contributions,
I'm not absolutely sure, but seems like Thread.currentThread().getContextClassLoader().getResourceAsStream("/plugin.xml") may solve your issue. If not, you'll have to create your own ClassLoader and resolve the issue there.
The simplies way is to move your jar in classpath to be the first containing Plugin.xml,
Another approach is to use getResource() to locate your jar file:
URL myJar=JmxPlugin.class.getResource("/"+JmxPlugin.class.getName().replace(".","/")+".class");
then use this URL to open jar file and extract Plugin.xml.

Categories

Resources