0

Basically I'm trying to load some image data into java as an ImageIcon object. I originally tried simply doing ImageIcon image = new ImageIcon(filename), but that made it so the images didn't load up when exported as a JAR file. The new way I've done it is as so:

private static ImageIcon getImage(String filename) {
    try {
        URL url = PacMan.class.getResource(filename);
        Image image = ImageIO.read(url);
        return new ImageIcon(image);
    }
    catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}

The error is because PacMan.class.getResource(filename) returns null. My directory is such that my PacMan class is in src/Model/PacMan and my images have the following file paths:

src/Model/PacMan_Images/PacMan_EAST, 
src/Model/PacMan_Images/PacMan_SOUTH, 
src/Model/PacMan_Images/PacMan_WEST, 
src/Model/PacMan_Images/PacMan_NORTH. 

Also, I've tried reverting back to using new ImageIcon(filepath) and the image loads up fine so I know the image exists in my directory. Anybody know what might be the problem?

Edit: My error is that I get an IllegalArgumentException thrown because I'm passing null as a parameter for ImageIO.read(url), because url is null.

halfer
  • 19,824
  • 17
  • 99
  • 186
  • 1
    Have you tried unzipping the jar to see what the file structure inside is? Also what is the value of filename? – Konrad Botor Jul 02 '18 at 22:04
  • What path are you passing `getImage`? `PacMan.class.getResource(filename)` is returning `null` because the named resource can't be found. Based on the available information, the resource name should be something like `/Model/PacMan_Images/PacMan_EAST` - remember, NEVER, EVER reference `src` in your code – MadProgrammer Jul 02 '18 at 22:05
  • *"Also, I've tried reverting back to using new ImageIcon(filepath) and the image loads up fine so I know the image exists in my directory"* - This is a side effect of using the direct path name (ie `src/Model/PacMan_Images/PacMan_EAST`) as `ImageIcon` uses the `String` to search for a file in the file system. Since a Jar'ed resource isn't a file, but a entry in Zip file, file references won't work – MadProgrammer Jul 02 '18 at 22:06
  • 1) For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). 2) `private static ImageIcon getImage(String filename)` Why is this method declared as `static`? It is likely getting the wrong class loader. – Andrew Thompson Jul 03 '18 at 02:21

2 Answers2

1

I'd be surprised if the path root "/src" was actually imported into your .jar. Please try this:

  1. Look inside the .jar. For example, use 7Zip to see the actual path for your files.

  2. Try changing your filename to "Model/PacMan_Images/PacMan_EAST".

  3. Look here for more details on Java getResource():

http://www.novixys.com/blog/read-file-resources-folder-java/

https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html

Java Swing: Displaying images from within a Jar

ADDENDUM:

  1. I would download 7-Zip and examine your .jar file just to become familiar with the format. It's just a .zip file ... but it's often useful to understand what's inside of it, and be able to modify it (if only for troubleshooting).

  2. Here's an excellent discussion of "Class.getResource" (which can take a "relative" resource name) vs. "absolute resource" (which MUST have the leading slash):

What is the difference between Class.getResource() and ClassLoader.getResource()?

  1. Finally, here's one suggestion for refactoring your code to avoid the compiler warning:

    private static ImageIcon getImage(String filename) {
        ImageIcon imageIcon = null;
        try {
            URL url = PacMan.class.getResource(filename);
            Image image = ImageIO.read(url);
            imageIcon = new ImageIcon(image);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
        return imageIcon;
    }
    

There are many other options, including just disabling that particular warning (e.g. @SuppressWarnings).

paulsm4
  • 114,292
  • 17
  • 138
  • 190
  • 1. The error occurs in my IDE. I rebuilt my artifacts and looked inside my .jar file and everything is exactly where it's supposed to be 2. I tried that. DId not work 3. I will look there thank you – stackUnderflow Jul 02 '18 at 22:11
  • Oh wait. I fixed it. The error was that I was passing as my filename Model/PacMan_Images/PacMan_EAST instead of /Model//PacMan_Images/PacMan_EAST. Turns out that extra / really makes a difference. Thank you to @MadProgrammer for your help, and everybody else who commented. I will try to see if this works for everything else, and whether I run into any more problems. Right now, it seems like I'm still getting an IOException thrown somewhere, but it might not be because of my getResource() function. – stackUnderflow Jul 02 '18 at 22:16
  • Also, does anyone know how to make it so I don't have to put a return null at the end of my code? It seems redundant, but I have to put it there because my return statement is out of scope so the compiler sees that as the method not necessarily returning a value – stackUnderflow Jul 02 '18 at 22:17
  • *"Turns out that extra / really makes a difference."* Of course it does! A resource string prefixed with `/` will cause the class loader to build a path from the root of the class path. Without the `/`, the string will be expected to point to a path starting from the **package of the calling class.** Programming is not random, and will not work that way. That's why it's important to understand the underlying logic rather than try random things in the hope they work. – Andrew Thompson Jul 03 '18 at 02:25
  • '"absolute resource" (which *must* have a leading slash)': that's not correct, and it's not what it says in your link. An absolute resource obtained via `Class.getResource()` must have a leading slash, by definition, but when obtained via `ClassLoader.getResource()` it is already deemed to have one, again by definition. – user207421 Jul 03 '18 at 02:26
  • @AndrewThompson You've made the same mistake. It is `Class.getResource()`, not `ClassLoader.getResource()`, that behaves as you describe. `ClassLoader.getResource()` has no option but to start at the top. – user207421 Jul 03 '18 at 02:28
1

The error was that I was passing as my filename Model/PacMan_Images/PacMan_EAST instead of /Model/PacMan_Images/PacMan_EAST. Turns out that extra / really makes a difference. Thank you to @MadProgrammer for your help, @paulsm4 with the extra resources, and everybody else who commented.