r/javahelp • u/Born-Ad4658 • 8d ago
Unsolved I need help with getResourceAsStream
u/wildjokers (reaching out to you because I saw you in this thread)
https://www.reddit.com/r/javahelp/comments/sypxqz/getresourceasstream_null_when_run_from_jar/
I'm trying to run a Isometric Tile game, from chapter 13 of Killer Games Programming in Java, a very old book.
I'm using Eclipse. I'm not sure what classpath means, but I think mine is set up as
Project
src
Images
Sounds
I'm getting these errors when I run:
Exception in thread "main" java.lang.NullPointerException
at java.base/java.io.Reader.<init>(Reader.java:168)
at java.base/java.io.InputStreamReader.<init>(InputStreamReader.java:88)
The relevant code is:
{
String imsFNm = IMAGE_DIR + fnm;
System.out.println("Reading file: " + imsFNm);
try {
InputStream in = this.getClass().getResourceAsStream(imsFNm);
BufferedReader br = new BufferedReader( new InputStreamReader(in));
// BufferedReader br = new BufferedReader( new FileReader(imsFNm));
String line;
The image file is defined in another class, and then piped into ImageLoader class, where it's appended to the directory, which is defined in ImageLoader class.
When I run, it's showing the correct directory in the console, so I believe getResourceAsStream is where it's being messed up.
I did right click on the images folder, Build Path > Add to Build Path.
I can provide more information, which will probably be needed.
1
u/_Super_Straight 8d ago
What is this? Spring? FX? CLI?
1
u/Born-Ad4658 8d ago edited 8d ago
Its not using a framework or library
I don't think the issue is with the actual code but rather how I have my project or files set up
2
u/_Super_Straight 8d ago
So plain java cli?
Tell us more about definition of IMAGE_DIR and fnm
1
u/Born-Ad4658 2d ago
I made a github repo
1
u/_Super_Straight 2d ago edited 2d ago
Ok. Which file has the problematic code?
Edit: NVM, found it. The problem is your directory structure. The
ImageLoaderclass is expecting the Images/ folder to be inside src/, and since it is not, it's throwing NullPointerException. Now you have two choices:
- Put your Images folder inside src, or
- Set
IMAGES_DIR = System.getProperty("user.dir")+"Images/";If you want to bundle your Images, Sounds etc. Folders inside your jar file, you'll need to put them inside a
resourcesfolder which should be located inside your src folder. I'd suggest reading about these folder structures online for more accurate folder structure. I'm away from system so I can't check it now.
1
u/Savings_Guarantee387 8d ago
I would bet inputstream in is null. But I would say just put a breakpoint and check...
1
u/awidesky 8d ago
- Is there any github repo that we can run and test the code?
- Try jdk 17 or higher, which gives you more information on NPE
- How is your images shipped?
Is the images folder got embedded inside the jar, or resides next to the jar?
I've struggled with same problem before, and the best solution for loading the resources is to put the resource folder next to the jar.
I build a project named ProjectPath that makes the path resolution easier too.
2
u/Born-Ad4658 2d ago edited 2d ago
I went ahead and make a github repo today.
I'm not sure the answer to question number 3. How do I find out please?
I did right-click on Images folder and select add to build path
Edit: So I'm doing reading, and only files inside the src folder are part of the Jar?
I also read that if you have a folder called res then you can also access them? Does that folder have to be called res? (I'm using Eclipse.)
I'm very confused, and not sure where to go to get an explanation.
https://stackoverflow.com/questions/48504303/getting-resources-outside-of-src-folder-in-a-jar-file
1
u/awidesky 1d ago
First, there are few things you need to check:
It seems you just added the codes from git manually of just uploaded it on GitHub.
In that case, project metadata files for Eclipse (like .project, .classpath, etc..) is not tracked(uploaded on GitHub), so other people who clones the repo may not import the project into Eclipse.
Using GitHub properly is good not only for other people who's interested on your work, but also for you in case you need to fetch your code and work from other computer.
Here's little how-to description about how to use git from Eclipse(I don't remember names of menus and buttons, so made AI to generate this):
- Create a Git Repository
If the project is not already a Git repository:
- Right-click the project in Project Explorer.
- Select Team → Share Project...
- Select Git.
- Select or create the repository for the project.
- Click Finish.
If the project is already a Git repository, Eclipse should detect it automatically. Do not initialize it again.
- Add Files to Git
- Right-click the project.
- Select Team → Add to Index.
Alternatively, open the Git Staging view:
- Window → Show View → Other... → Git → Git Staging
- Move the desired files from Unstaged Changes to Staged Changes.
Check that generated files are not being added accidentally. Add a .gitignore if necessary.
- Create a Commit
In the Git Staging view:
- Review the staged files.
- Enter a commit message, for example: Initial commit
- Click Commit.
- Push to the Remote
- Right-click the project.
- Select Team → Push Branch 'main'...
If the local branch is currently named master, either push it as master or rename it to main first.
For a new repository, configure:
Local branch: main
Remote branch: main
Remote: originThen click Next and Finish/Push.
- Verify
Refresh the project and check the Git history in Eclipse.
You can also verify the remote configuration from:
Git Repositories
→ Remotes
→ originTry it when you have time. assistant of AI would help if you get some error.
Second, it seems you're just export it via Eclipse's export->runnable jar.
I suggest you learn about maven, because:
- if you want to get a job or learn deeply in Java, you'll have to study about it anyway.
- It automatically standardizes build, test, dependency management(for when you need another library to use), and packaging process.
Well, now let's talk about the actual problem on our hand.
First, your path looks like "Images/foo.jpg". That's a relative path. Absolute path looks like "C:\User\user\Documents\foo.jpg" or "/Users/user/Documents/foo.jpg".
When you use relative path, the path is resolved with your console's current path, which is likely to change in many reasons.
Let's say your jar file is in "C:\User\user\Documents\foo.jar", images are in "C:\User\user\Documents\Images\img.jpg", and you use the path as "Images/img.jpg"
When your console's cd is "C:\User\user\Documents", it'll work.
If it's anything else, like "C:\User\user", it won't work.
That's why we do one of the 2 options:
- putting image inside of jar, and get like InputStream in = getClass().getResourceAsStream("/Images/hello.jpg");
- Put images next to jar file, get the absolute path of jar file, and combine it to get absolute path.
1 is simplest but does not work most of the time.
It needs the images to reside inside of the jar file, and you should extract the jar file and check if the .class file in the same directory with Images folder.
2 works all the time, but you need to find absolute path of the jar.
After that, put your Images folder next to the jar, and resolve the paths to get completed one.
I made a library called [ProjectPath](https://github.com/awidesky/ProjectPath) that find the path to resouces inside of Eclipse project and jar file before.
If you're familiar with maven you can use it easily, else take a look in [JarPath.java](https://github.com/awidesky/ProjectPath/blob/master/src/main/java/io/github/awidesky/projectPath/JarPath.java).
It is a tricky stuff since you need to take care of multiple thing(some solution works when you’re running a packaged jar but not when you run the project from Eclipse, others are completely opposite..)
And also I think I tried to put little too much information right here.
Just take some time reading this, don't get mad when it does not work, come back here and tell me what happened.
Just make sure you understand each step before you do it, or you'll get lost and codebase will be too screwed up to be fixed.
1
u/Born-Ad4658 1d ago edited 1d ago
I think I may be on the way to something.
I made a new project, and this time, instead of creating the folders in File Explorer of my PC, I did it from the Explorer tab from Eclipse, and then clicked used as Source Folder.
This time, I noticed that those files populated in the bin folder, when they did not do that before.
I think I ran it before I did use as Source Folder for the other folders, because they're in my Projects src project, instead of under res/Images like they should be.
How do I get the bin folder to refresh please?
Edit: So I think I fixed it, because now I'm just getting errors for a different class.
I removed the folders from source and re-added, but they all still just showed up in the bin folder instead of under resources.
So I took out the directory references completely and just went by the filename.
The person who made this book probably wasn't using Eclipse, or maybe it wasn't out yet lol.
1
u/awidesky 23h ago
I did not quite understand your last paragraph, but it seems you managed to make Eclipse consider the resource files as one of source codes, and move it to bin folder.
But, if you still use that relative path, it may have some problem.
1. It won't work in other working directory.
The reason it's working now is that when you run the project from Eclipse, it spawns a process with bin folder as its working directory, and your resource is also in that bin folder.
If you run the project from console in other working directory, it may not work.
2. It won't work when running as jar file.
Because the resources are packaged into jar file, so technically they don't have a path.
In that case you must use getResourceAsStream I introduced before.2
u/Born-Ad4658 23h ago edited 22h ago
Understood. Thank you.
I'm going to start work on another example project from a book that uses Maven, so ill learn as I go.
1
1
u/edwbuck 7d ago edited 7d ago
Jar files are Zip files with a few additional features.
- Did you copy the jar file to an empty directory and unzip it?
- Was the item you were trying to load in the Jar?
- Was it in the correct path within that Jar?
- Did the upper / lower case of the directories and names match?
When running with a ClassPath that matches a directory, it will use the un-Jar'd directory tree to find the resource; but, once you run it within a Jar, it will use the path within the Jar file.
And if you are attempting to do "java -jar jarfile.jar" to run the program, remember that "java -jar" ignores the directory entries outside of the Jar file, because the class loader is loading from within the Jar file, so it can't see items outside of the Jar file.
1
u/ChaiTRex 7d ago
You should look at the stack trace and go down from the top until you see a file that you wrote. The stack trace you showed here doesn't help.
1
u/Born-Ad4658 2d ago
I made a github repo.
1
u/ChaiTRex 2d ago edited 2d ago
No, I mean, in order to get better at debugging your code, you should personally look at the stack trace because it can really help you.
You said that you got a stack trace like:
Exception in thread "main" java.lang.NullPointerException at java.base/java.io.Reader.<init>(Reader.java:168) at java.base/java.io.InputStreamReader.<init>(InputStreamReader.java:88)That's only the beginning of the stack trace.
Reader.javaandInputStreamReader.javain those lines are classes that you didn't write. You should keep going through the lines until you see the first line that is a class that you wrote.You'll see something like
MyProject.java:33. This tells you that line 33 inMyProject.javacaused the error. Since it's aNullPointerException, that means you had a method call or field access on an object that was set tonullor that you passed a variable set tonullinto a method that expects something that's notnull.So, for example, if you did
InputStreamReader reader = new InputStreamReader(myInputStream);,myInputStreamis probably set tonullfor some reason.1
u/Born-Ad4658 2d ago
I know the line.
I also just threw in the a throw illegalargumentexception and confirmed that the inputstream is coming up null.
Its not finding the file
I think my next step is seeing if I can get this to run
https://howtodoinjava.com/java/io/read-file-from-resources-folder/
1
u/KillerCodeMonky 7d ago
It's highly likely that the path being specified by imsFNm is not properly resolving to the resource. You are using the version of this method provided by Class instead of ClassLoader. That version of the method has extra processing that occurs on the path.
What is the value of IMAGE_DIR? I will be able to help you more once I know that.
1
u/Born-Ad4658 2d ago
I made a github repo.
1
u/KillerCodeMonky 2d ago
So in
ImagesLoader, you setIMAGE_DIR = "Images/". Since this is a relative path, theClass.getResourcemethod will prepend it with the class' package. Now your classes are not actually in a package, so I'm not sure how that interacts. However, the first thing I would try is instead use:IMAGE_DIR = "/Images/"
Note the extra
/in the front. This makes it an absolute resource path and it will look forImagesas the class path root.1
u/Born-Ad4658 2d ago
That did not work.
I right clicked the folder went to Properties > Java Build Path and every thing is listed.
Errors I'm getting:
Linking the MIDI sequencer and synthesizer
Problem with Sounds/Mission_Impossible.mid
-- mi/Mission_Impossible.mid
Reading file: /Images/imsInfo.txt
Exception in thread "main" java.lang.NullPointerException
at java.base/java.io.Reader.<init>(Reader.java:168) at java.base/java.io.InputStreamReader.<init>(InputStreamReader.java:88) at ImagesLoader.loadImagesFile(ImagesLoader.java:97) at ImagesLoader.<init>(ImagesLoader.java:66) at AlienTilesPanel.<init>(AlienTilesPanel.java:109) at AlienTiles.<init>(AlienTiles.java:73) at AlienTiles.main(AlienTiles.java:114)I will research and look at this more.
1
u/KillerCodeMonky 1d ago
I'm not sure how much more I'll be able to help, because you're using an unconventional project structure and no project definition file. I'm guessing you're directly defining this project in Eclipse or IntelliJ. A typical Maven project would your have classes under
src/main/javaand your resources undersrc/main/resources. But as is I can't reliably recreate your environment.1
u/Born-Ad4658 1d ago
Is Maven a necessity for most projects?
1
u/KillerCodeMonky 1d ago
If you want your project to reliably be worked on by others, then yes: Having a well known, common format for defining the project is a necessity. Maven and Gradle are the most popular by far.
I'm not saying you need to use them, even though it would take a grand total of about 5 minutes to reorganize your project for it. But I am saying that myself, from outside your computer, cannot reliably tell you anything more about why your project is not able to resolve resources, because I have no way to reproduce how you are defining that project and its resources.
1
u/Cienn017 7d ago
this.getClass().getResourceAsStream is relative to current classpath (the directory where the class is).
if you class is at "com/package/MyClass.class" (the src directory doesn't count) then you need to place your image in "com/package/", in other words, remove the IMAGE_DIR constant and it should work.
•
u/AutoModerator 8d ago
Please ensure that:
You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions.
Trying to solve problems on your own is a very important skill. Also, see Learn to help yourself in the sidebar
If any of the above points is not met, your post can and will be removed without further warning.
Code is to be formatted as code block (old reddit: empty line before the code, each code line indented by 4 spaces, new reddit: https://i.imgur.com/EJ7tqek.png) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc.
Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit.
Code blocks look like this:
You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above.
If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures.
To potential helpers
Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice.
I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.