In this example we will see how to construct a Properties
object by loading the property files from different sources using multiple class loaders. Given a resource name, it mostly tries to find the resources from the application’s classpath. The current Thread ClassLoader is given preference. Next preference is given to the class loader that has loaded the current class an then to the system class loader.
We want to load application.properties. For example sake, we have one application.properties in the classpath.
src/application.properties:
article=java properties loader blog=xyz
And the second application.properties is in a jar file.
jar/application.properties:
blog=javarticles.com
The jar command that bundles the properties file as a jar file.
createJar.bat:
jar cfe app.jar app application.properties
We will create a custom class loader based on the above jar file.
CustomClassLoader:
package com.javarticles.properties; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; public class CustomClassLoader extends URLClassLoader { public CustomClassLoader(ClassLoader parent) throws MalformedURLException { super(new URL[] { new File(System.getProperty("user.dir") + "/jar/app.jar").toURI().toURL() }, parent); } public CustomClassLoader() throws MalformedURLException { super(new URL[] { new File(System.getProperty("user.dir") + "/jar/app.jar").toURI().toURL() }); } }
We will then set the custom class loader as the current thread’s context loader. Our example contains two instances of custom loader. The first one has the default parent which is the system class loader.
In the second instance, we set the parent to null which means its not going to delegate the call to its parent, so it will only return the resource found in the jar file and not the one in classpath.
Method findPropertyUrls()
will return a collection of URLs matching the resource name. If no resources could be found, then this will be empty. Once we have the resources, we will iterate through each URL, open the stream, and load the properties file.
InputStream in = url.openStream(); properties.load(in);
PropertyLoaderExample:
package com.javarticles.properties; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.Collection; import java.util.Enumeration; import java.util.LinkedHashSet; import java.util.Properties; public class PropertyLoaderExample { Properties properties; public static void main(String[] args) throws MalformedURLException { Thread.currentThread().setContextClassLoader(new CustomClassLoader()); PropertyLoaderExample propLoaderExample = new PropertyLoaderExample(); propLoaderExample.load("application.properties"); System.out.println("-----------------------------------------------------------"); System.out.println("Fetch properties"); propLoaderExample.printProperty("blog"); propLoaderExample.printProperty("article"); System.out.println("-----------------------------------------------------------"); System.out.println("Reload properties with custom loader's parent set to null"); Thread.currentThread().setContextClassLoader(new CustomClassLoader(null)); propLoaderExample = new PropertyLoaderExample(); propLoaderExample.load("application.properties"); System.out.println("-----------------------------------------------------------"); System.out.println("Fetch properties"); propLoaderExample.printProperty("blog"); propLoaderExample.printProperty("article"); } void printProperty(String key) { System.out.println(key + "=" + properties.getProperty(key)); } public void load(final String propertiesFileName) { final Properties properties = new Properties(); Collection propertyUrls = findPropertyUrls(propertiesFileName); System.out.println("-----------------------------------------------------------"); System.out.println("Start load property resources"); for (final URL url : propertyUrls) { System.out.println("Load " + url); InputStream in = null; try { in = url.openStream(); properties.load(in); } catch (final IOException ioe) { System.out.println("Unable to " + url.toString() + " exception " + ioe); } finally { if (in != null) { try { in.close(); } catch (final IOException ioe) { System.out.println("Unable to close " + url.toString() + " exception " + ioe); } } } } this.properties = properties; } private static Collection findPropertyUrls(final String resource) { System.out.println("Find property resources"); final ClassLoader[] classloaders = {Thread.currentThread().getContextClassLoader(), PropertyLoaderExample.class.getClassLoader(), ClassLoader.getSystemClassLoader()}; final Collection propResources = new LinkedHashSet(); for (final ClassLoader cl : classloaders) { if (cl != null) { System.out.println("class loader is " + cl); try { final Enumeration resourceEnum = cl.getResources(resource); while (resourceEnum.hasMoreElements()) { URL url = resourceEnum.nextElement(); System.out.println("Add resource " + url); propResources.add(url); } } catch (final IOException e) { e.printStackTrace(); } } } return propResources; } }
As you can see in the first case where the custom classloader’s parent is the default class loader, the resource found in claspath is loaded first and then the resource from the jar file which is why the property file in jar overrides the key/value pair of the resource found in classpath.
In the second case, the custom class loader’s parent is set to null which means the resource in jar file will be loaded first and then the resource found in the classpath.
Output:
Find property resources class loader is [email protected] Add resource file:/C:/javarticles_ws/javaPropertyLoaderExample/bin/application.properties Add resource jar:file:/C:/javarticles_ws/javaPropertyLoaderExample/jar/app.jar!/application.properties class loader is [email protected] Add resource file:/C:/javarticles_ws/javaPropertyLoaderExample/bin/application.properties class loader is [email protected] Add resource file:/C:/javarticles_ws/javaPropertyLoaderExample/bin/application.properties ----------------------------------------------------------- Start load property resources Load file:/C:/javarticles_ws/javaPropertyLoaderExample/bin/application.properties Load jar:file:/C:/javarticles_ws/javaPropertyLoaderExample/jar/app.jar!/application.properties ----------------------------------------------------------- Fetch properties blog=javarticles.com article=java properties loader ----------------------------------------------------------- Reload properties with custom loader's parent set to null Find property resources class loader is [email protected] Add resource jar:file:/C:/javarticles_ws/javaPropertyLoaderExample/jar/app.jar!/application.properties class loader is sun.misc.Launcher$AppClassL[email protected] Add resource file:/C:/javarticles_ws/javaPropertyLoaderExample/bin/application.properties class loader is [email protected] Add resource file:/C:/javarticles_ws/javaPropertyLoaderExample/bin/application.properties ----------------------------------------------------------- Start load property resources Load jar:file:/C:/javarticles_ws/javaPropertyLoaderExample/jar/app.jar!/application.properties Load file:/C:/javarticles_ws/javaPropertyLoaderExample/bin/application.properties ----------------------------------------------------------- Fetch properties blog=xyz article=java properties loader
Download the source code
This was an example about loading properties file in java.