Slick2D automatically load images?

So, while I was working on a game I was making, I made myself a little Art class. Here it is:

package com.kirc.drilldescent;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

import org.newdawn.slick.AngelCodeFont;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader;

public class Art
{
	
//	public static Image dirtTile;
	private static Map<String,Image> loadedImages;
	private static AngelCodeFont font;
	/**
	 * Loads all .png images located in the /res folder.
	 * @throws SlickException
	 */
	public static void init() throws SlickException {
		
//		dirtTile = new Image("res/dirtTile.png");
		loadedImages = new HashMap<>();
		try
		{
			URI uri = new URI(ResourceLoader.getResource("res").toString());
			File[] files = new File(uri).listFiles(new FilenameFilter(){

				@Override
				public boolean accept(File dir, String name)
				{
					if(name.endsWith(".png"))
						return true;
					return false;
				}
				
			});
			
			for(File f:files)
			{
				FileInputStream fis = new FileInputStream(f);
				Image image = new Image(fis, "res/"+f.getName(), false);
				loadedImages.put(f.getName(), image);
			}
		} catch (URISyntaxException | FileNotFoundException e)
		{
			System.err.println("UNABLE TO LOAD IMAGES FROM RES FOLDER!");
			e.printStackTrace();
		}
		
		font = new AngelCodeFont("res/bitmapfont.fnt",Art.get("bitmapfont.png"));

	}
	/**
	 * 
	 * @param filename The filename of the image in the /res folder
	 * @return The loaded image of that filename
	 */
	public static Image get(String filename)
	{
		return loadedImages.get(filename);
	}
	
	public static AngelCodeFont getFont()
	{
		return font;
	}
}

Unfortunately, while this will automatically load all images in my res/ directory (and let me load them once and only once), it won’t work if I decide to pack everything into a .jar. I was wondering if anyone used a nicer pattern to keep all their game art organized and easy to access in their code. I took the lazy way because I didn’t want to add a line for every single one of my images. (Also, if you know how to adapt this to a .jar that’d be nice to share.)

You can iterate over the entries in a jar/zip file with

import java.io.FileInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

    ZipInputStream zis = new ZipInputStream(new FileInputStream(pathToZip));
    for (ZipEntry ze; (ze = zis.getNextEntry()) != null;) {
      System.out.println(ze.getName());
    }

That way you can enumerate all paths that start with “res/”, ending with “.png” and load them using ClassLoader.getResourceAsStream(path).

Okay, but how do I get “pathToZip” to point to itself without having to keep the .jar strictly named? (If you use the .jar’s name then you can’t rename it or it won’t work).

You could search it in the classpath.

Well, got an answer from StackExchange. Figured i’d post the working code here for future reference:

package com.kirc.drilldescent.res;

import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;

import org.newdawn.slick.AngelCodeFont;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.util.ResourceLoader;

public class Art
{
	
	private static Map<String,Image> loadedImages;
	private static AngelCodeFont font;
	/**
	 * Loads all .png images located in source folders.
	 * @throws SlickException
	 */
	public static void init() throws SlickException {
		
		loadedImages = new HashMap<>();
		try
		{
			URL url = Art.class.getResource("../res");
			//use filesystem loading
			if(url != null)
			{
				File resDir = new File(new URI(url.toString()));
				File[] files = resDir.listFiles(new FilenameFilter(){
					@Override
					public boolean accept(File dir, String name)
					{
						if(name.endsWith(".png"))
							return true;
						return false;
					}
					
				});
				
	
				for(File f:files)
				{
					FileInputStream fis = new FileInputStream(f);
					Image image = new Image(fis, f.getName(), false);
					loadedImages.put(f.getName(), image);
				}
			}
			//use jar loading
			else
			{
				
				URLConnection uc = ClassLoader.getSystemResource("com/kirc/drilldescent/res").openConnection();
				if(uc instanceof JarURLConnection)
				{
					JarURLConnection juc = (JarURLConnection) uc;
					JarFile jarFile = juc.getJarFile();
					Enumeration<JarEntry> jarFileEntries = jarFile.entries();
					while (jarFileEntries.hasMoreElements()) {
						JarEntry jarEntry = jarFileEntries.nextElement();
						String jarEntryName = jarEntry.getName();
						if(jarEntryName.startsWith("com/kirc/drilldescent/res") && jarEntryName.endsWith(".png"))
						{
							Image image = new Image(jarEntryName);
							loadedImages.put(jarEntryName.replace("com/kirc/drilldescent/res/",""),image);
						}
						
					}
				}
				
			}
		} catch (URISyntaxException | IOException e)
		{
			e.printStackTrace();
		}
		
		font = new AngelCodeFont("com/kirc/drilldescent/res/bitmapfont.fnt",Art.get("bitmapfont.png"));

	}
	/**
	 * 
	 * @param filename The filename of the image in the /res folder
	 * @return The loaded image of that filename
	 */
	public static Image get(String filename)
	{
		return loadedImages.get(filename);
	}
	
	public static AngelCodeFont getFont()
	{
		return font;
	}
}

EDIT: Well, it works before I try to package the natives with jarsplice. After that, ClassLoader.getSystemResource fails to return anything. What does jarsplice do to prevent this from working? (I haven’t actually got a clear idea what getSystemResource does either)