[java] Preferred way of loading resources in Java

I would like to know the best way of loading a resource in Java:

  • this.getClass().getResource() (or getResourceAsStream()),
  • Thread.currentThread().getContextClassLoader().getResource(name),
  • System.class.getResource(name).

This question is related to java resources

The answer is


I tried a lot of ways and functions that suggested above, but they didn't work in my project. Anyway I have found solution and here it is:

try {
    InputStream path = this.getClass().getClassLoader().getResourceAsStream("img/left-hand.png");
    img = ImageIO.read(path);
} catch (IOException e) {
    e.printStackTrace();
}

I search three places as shown below. Comments welcome.

public URL getResource(String resource){

    URL url ;

    //Try with the Thread Context Loader. 
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Let's now try with the classloader that loaded this class.
    classLoader = Loader.class.getClassLoader();
    if(classLoader != null){
        url = classLoader.getResource(resource);
        if(url != null){
            return url;
        }
    }

    //Last ditch attempt. Get the resource from the classpath.
    return ClassLoader.getSystemResource(resource);
}

Well, it partly depends what you want to happen if you're actually in a derived class.

For example, suppose SuperClass is in A.jar and SubClass is in B.jar, and you're executing code in an instance method declared in SuperClass but where this refers to an instance of SubClass. If you use this.getClass().getResource() it will look relative to SubClass, in B.jar. I suspect that's usually not what's required.

Personally I'd probably use Foo.class.getResourceAsStream(name) most often - if you already know the name of the resource you're after, and you're sure of where it is relative to Foo, that's the most robust way of doing it IMO.

Of course there are times when that's not what you want, too: judge each case on its merits. It's just the "I know this resource is bundled with this class" is the most common one I've run into.


I know it really late for another answer but I just wanted to share what helped me at the end. It will also load resources/files from the absolute path of the file system (not only the classpath's).

public class ResourceLoader {

    public static URL getResource(String resource) {
        final List<ClassLoader> classLoaders = new ArrayList<ClassLoader>();
        classLoaders.add(Thread.currentThread().getContextClassLoader());
        classLoaders.add(ResourceLoader.class.getClassLoader());

        for (ClassLoader classLoader : classLoaders) {
            final URL url = getResourceWith(classLoader, resource);
            if (url != null) {
                return url;
            }
        }

        final URL systemResource = ClassLoader.getSystemResource(resource);
        if (systemResource != null) {
            return systemResource;
        } else {
            try {
                return new File(resource).toURI().toURL();
            } catch (MalformedURLException e) {
                return null;
            }
        }
    }

    private static URL getResourceWith(ClassLoader classLoader, String resource) {
        if (classLoader != null) {
            return classLoader.getResource(resource);
        }
        return null;
    }

}