How to Load Resources from Classpath in Java with Example
Classpath in Java is not only used to load .class files, but also can be used to load resources e.g. properties file, images, icons, thumbnails, or any binary content. Java provides API to read these resources as InputStream or URL. Suppose, you have a properties file inside config folder of your project, and you want to load that properties file, how do you do that? Similarly, you have icons and thumbnails for your web applications on icons directory of your project, how do you load them? Answer is by using java.lang.Class’getResource() and getResourceAsStream() method. These method accepts path of resource as String and returns URL and InputStream respectively. You can obtain a reference of Class by calling either getClass() method or by using class literal. If you have an object, then you can call getClass() because its a non-static method, on the other hand, if you don’t have any object, you can simply use .class with name of any class e.g. Sample.class will give you reference of java.lang.Class. These methods are available from JDK 1.1 and you can even use them anywhere you have access to core Java library. If you are creating J2ME games or application, you can use these method to load icons and tiles for your game, and all other resource for your application as well.
How does getResourceAsStream works
Internally this method delegate the loading request of resource to its class loader. If you call getResourceAsStream() method on an object which is loaded by BootStrap ClassLoader then it will delegate it to ClassLoader.getSystemResourceAsStream(java.lang.String) method. We pass path of resource to this method but rules for searching resources associated with a given class are implemented by the defining class loader of the class. Since you can pass both absolute and relative path to Class.getResourceAsStream(), but ClassLoader.getResourceAsStream() takes an absolute path, that’s why an absolute resource name is constructed from the given resource name using following algorithm :
If the name begins with a ‘/’ (‘\u002f’), then the absolute name of the resource is the portion of the name following the ‘/’. Otherwise, the absolute name is of the following form:
modified_package_name/name where the modified_package_name is the package name of this object with ‘/’ substituted for ‘.’ (‘\u002e’).
This means, the resource name passed to the method should look like /com/abc/config/app.properties if the app.properties is stored in the com.abc.config package instead of the current class’s.
If you look at the code of java.lang.Class in Eclipse IDE by using short-cut Ctrl+T and typing java.lang.Class, you can see how this method works :
public InputStream getResourceAsStream(String name) { name = resolveName(name); ClassLoader cl = getClassLoader0(); if (cl==null) { // A system class. return ClassLoader.getSystemResourceAsStream(name); } return cl.getResourceAsStream(name); }
This algorithm is implemented at resolveName() method, as seen below :
/** * Add a package name prefix if the name is not absolute Remove leading "/" * if name is absolute */ private String resolveName(String name) { if (name == null) { return name; } if (!name.startsWith("/")) { Class c = this; while (c.isArray()) { c = c.getComponentType(); } String baseName = c.getName(); int index = baseName.lastIndexOf('.'); if (index != -1) { name = baseName.substring(0, index).replace('.', '/') +"/"+name; } } else { name = name.substring(1); } return name; }
Main problem comes while loading resource using getResourceAsStream() method is NullPointerException, because this method return null if its not able to find the resource. In following example, we have a Eclipse project, and I have created a properties file called app.properties inside config directory. Now to load that file, I just need to pass “app.properties”, if I pass anything like “config/app.properties” or “/config/app.properties” getResourceAsStream() will return null, and code will subsequently throw NullPointerException as shown below :
Exception in thread "main" java.lang.NullPointerException at java.util.Properties$LineReader.readLine(Unknown Source) at java.util.Properties.load0(Unknown Source) at java.util.Properties.load(Unknown Source) at Test.main(Test.java:29)
to avoid this error you must check output of getResourceAsStream() before using it, defensive programming is there just because of this kind of methods.
Java Program to load Resource from Classpath
Here is our complete Java program to load images, resources, text file or binary file from classpath in Java, resource can be anything, what is important is that it must be accessible.
package test; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Properties; /** * Java Program to demonstrate how to load resources e.g. properties file from * classpath. There are two ways to load resources in Java, one by using * getResourceAsStream() and getResource() method from java.lang.Class. Main * difference between these two methods are that one returns an InputStream * while other returns a URL object. * * @author Javin Paul */ public class ResourceLoader{ public static void main(String args[]) { // loading resource using getResource() method InputStream in = Test.class.getResourceAsStream("app.properties"); Properties config = new Properties(); try { config.load(in); System.out.println(config.getProperty("name")); System.out.println(config.getProperty("version")); } catch (IOException e1) { e1.printStackTrace(); } // loading resource using getResourceAsStream() method URL resourceURL = Test.class.getResource("app.properties"); Properties appConfig = new Properties(); try { appConfig.load(resourceURL.openStream()); System.out.println(appConfig.getProperty("name")); System.out.println(appConfig.getProperty("version")); } catch (IOException e) { e.printStackTrace(); } } } Output: SampleApp 1.0.0 SampleApp 1.0.0
If you look closely you will find that we have used both getResource() and getResourceAsStream() method to load resource from classpath in Java, in this case just properties file. First example looks more cleaner than second example because we don’t need to open an explicit stream, getResourceAsStream() method returns an InputStream, which can be used anywhere. That’s all on how to load resources from class-path in Java.
Reference: | How to Load Resources from Classpath in Java with Example from our JCG partner Javin Paul at the Javarevisited blog. |