Meeesh
Meeesh

Reputation: 1042

Loading image from source folder returned as null

Hello I have a problem with importing an image from my resources folder. I have looked all over google (or so I think) and I have no idea what I am doing wrong.

All help is appreciated thanks

Here is the picture of my java project:

Here is my picture

Here is my Game Code:

public Game(){

    handler = new Handler();
    this.addKeyListener(new KeyInput(handler));

    new Window(WIDTH, HEIGHT, "Testing", this);

    BufferedImageLoader loader = new BufferedImageLoader();
    level = loader.loadImage("/level.png");

    hud = new HUD();
    spawn = new Spawn(handler, hud);
    r = new Random();
    walls = new WallsMap(handler);
    cam = new Camera(0, 0);

    walls.render();  
    handler.addObject(new Player(WIDTH/2-32, HEIGHT/2-32, ID.Player, handler));
}

Finally here is my BufferedImageLoader class:

    public class BufferedImageLoader {

    private BufferedImage image;

    public BufferedImage loadImage(String path){
        try {
            image =  ImageIO.read(getClass().getClassLoader().getResourceAsStream(path));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return image;
    }
}

Upvotes: 3

Views: 527

Answers (2)

thejonwithnoh
thejonwithnoh

Reputation: 662

To solve your particular problem, either of these two options should work so that the resource can be properly located:

  • Remove the call to getClassLoader() from your loadImage method so that the call is just getClass().getResourceAsStream(path) -OR-
  • Remove the slash from "/level.png" so that your call to loadImage looks like loader.loadImage("level.png")

However, in general, I agree with mastercork889, that it is better practice to organize your resources into packages as well.

EDIT:

In response to mastercork889's comment saying that my answer should be AND instead of OR, I thought I should elaborate on why it is indeed exclusive OR. I would have just commented, but I'm still too new to stack overflow to be allowed to comment, and this is quite a bit of information anyway :)

Removing the call to getClassLoader() works because then you're using the getResourceAsStream() method from the Class class, which does extra work before delegation to the getResourceAsStream() method from the ClassLoader class.

From the Java API:

Before delegation, an absolute resource name is constructed from the given resource name using this algorithm:

  • If the name begins with a '/' ('\u002f'), then the absolute name of the resource is the portion of the name following the '/'.

Since your resource isn't in a package, and is at the top level of a source folder (it looks like res is an "Eclipse Source Folder"), the level.png portion following the slash will adequately identify the location of the resource in an absolute way.

OR

Removing the slash from "/level.png" also works because then when the object's class loader (which should be the system class loader) looks for the resource, it will attempt to resolve your resource in an absolute way. The special handling of the slash at the beginning is behavior that is specific to the getResourceAsStream() method in Class, not ClassLoader.

The reason that AND won't work, is because if you call the getResourceAsStream() method from Class and remove the slash, then it will attempt to locate the resource in the same package that the associated class is located in. If you choose to go with the AND option, then you would need to move level.png into the com.plat.gfx package.

As a final point, I have built a small test program that followed the same format as your example, and once I followed one of the two suggestions, it worked for me.

The subtleties of resources, classes, and class loaders can be quite tricky. Good luck with your project!

Upvotes: 4

TheBrenny
TheBrenny

Reputation: 527

Don't worry about putting images in a specific folder. Instead put them also in the src folder under a specific package: com.plat.res

I find that putting images in a specific package makes the package hierarchy look much more efficient, and less spaghetti-like.

Also a note on package conventions: domain-extension.domain.main-program.etc. My package hierarchy looks like this:

com.brennytizer.jumg
com.brennytizer.jumg.res
com.brennytizer.jumg.engine
com.brennytizer.jumg.level
com.brennytizer.jumg.level.maps

If you don't have a domain, write in what you think your domain would be (if you were to buy it in the future), or just use your (backwards) name:

My name is Jarod Brennfleck, writing program foobar, my package would be: brennfleck.jarod.foobar.

Once in there use the ImageIO class: ImageIO.read(Game.class.getResourceAsStream("/com/plat/res/leve.png"));

Upvotes: 2

Related Questions