Tutorial :URL to load resources from the classpath in Java


In Java, you can load all kinds of resources using the same API but with different URL protocols:

file:///tmp.txt  jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class  

This nicely decouples the actual loading of the resource from the application that needs the resource, and since a URL is just a String, resource loading is also very easily configurable.

Is there a protocol to load resources using the current classloader? This is similar to the Jar protocol, except that I do not need to know which jar file or class folder the resource is coming from.

I can do that using Class.getResourceAsStream("a.xml"), of course, but that would require me to use a different API, and hence changes to existing code. I want to be able to use this in all places where I can specify a URL for the resource already, by just updating a property file.


Intro and basic Implementation

First up, you're going to need at least a URLStreamHandler. This will actually open the connection to a given URL. Notice that this is simply called Handler; this allows you to specify java -Djava.protocol.handler.pkgs=org.my.protocols and it will automatically be picked up, using the "simple" package name as the supported protocol (in this case "classpath").


new URL("classpath:org/my/package/resource.extension").openConnection();  


package org.my.protocols.classpath;    import java.io.IOException;  import java.net.URL;  import java.net.URLConnection;  import java.net.URLStreamHandler;    /** A {@link URLStreamHandler} that handles resources on the classpath. */  public class Handler extends URLStreamHandler {      /** The classloader to find resources from. */      private final ClassLoader classLoader;        public Handler() {          this.classLoader = getClass().getClassLoader();      }        public Handler(ClassLoader classLoader) {          this.classLoader = classLoader;      }        @Override      protected URLConnection openConnection(URL u) throws IOException {          final URL resourceUrl = classLoader.getResource(u.getPath());          return resourceUrl.openConnection();      }  }  

Launch issues

If you're anything like me, you don't want to rely on a property being set in the launch to get you somewhere (in my case, I like to keep my options open like Java WebStart - which is why I need all this).


Manual code Handler specification

If you control the code, you can do

new URL(null, "classpath:some/package/resource.extension", new org.my.protocols.classpath.Handler(ClassLoader.getSystemClassLoader()))  

and this will use your handler to open the connection.

But again, this is less than satisfactory, as you don't need a URL to do this - you want to do this because some lib you can't (or don't want to) control wants urls...

JVM Handler registration

The ultimate option is to register a URLStreamHandlerFactory that will handle all urls across the jvm:

package my.org.url;    import java.net.URLStreamHandler;  import java.net.URLStreamHandlerFactory;  import java.util.HashMap;  import java.util.Map;    class ConfigurableStreamHandlerFactory implements URLStreamHandlerFactory {      private final Map<String, URLStreamHandler> protocolHandlers;        public ConfigurableStreamHandlerFactory(String protocol, URLStreamHandler urlHandler) {          protocolHandlers = new HashMap<String, URLStreamHandler>();          addHandler(protocol, urlHandler);      }        public void addHandler(String protocol, URLStreamHandler urlHandler) {          protocolHandlers.put(protocol, urlHandler);      }        public URLStreamHandler createURLStreamHandler(String protocol) {          return protocolHandlers.get(protocol);      }  }  

To register the handler, call URL.setURLStreamHandlerFactory() with your configured factory. Then do new URL("classpath:org/my/package/resource.extension") like the first example and away you go.

JVM Handler Registration Issue

Note that this method may only be called once per JVM, and note well that Tomcat will use this method to register a JNDI handler (AFAIK). Try Jetty (I will be); at worst, you can use the method first and then it has to work around you!


I release this to the public domain, and ask that if you wish to modify that you start a OSS project somewhere and comment here with the details. A better implementation would be to have a URLStreamHandlerFactory that uses ThreadLocals to store URLStreamHandlers for each Thread.currentThread().getContextClassLoader(). I'll even give you my modifications and test classes.


URL url = getClass().getClassLoader().getResource("someresource.xxx");  

That should do it.


You can also set the property programmatically during startup:

final String key = "java.protocol.handler.pkgs";  String newValue = "org.my.protocols";  if (System.getProperty(key) != null) {      final String previousValue = System.getProperty(key);      newValue += "|" + previousValue;  }  System.setProperty(key, newValue);  

Using this class:

package org.my.protocols.classpath;    import java.io.IOException;  import java.net.URL;  import java.net.URLConnection;  import java.net.URLStreamHandler;    public class Handler extends URLStreamHandler {        @Override      protected URLConnection openConnection(final URL u) throws IOException {          final URL resourceUrl = ClassLoader.getSystemClassLoader().getResource(u.getPath());          return resourceUrl.openConnection();      }  }  

Thus you get the least intrusive way to do this. :) java.net.URL will always use the current value from the system properties.


I think this is worth its own answer - if you're using Spring, you already have this with

Resource firstResource =      context.getResource("http://www.google.fi/");  Resource anotherResource =      context.getResource("classpath:some/resource/path/myTemplate.txt");  

Like explained in the spring documentation and pointed out in the comments by skaffman.


I've created a class which helps to reduce errors in setting up custom handlers and takes advantage of the system property so there are no issues with calling a method first or not being in the right container. There's also an exception class if you get things wrong:

CustomURLScheme.java:  /*   * The CustomURLScheme class has a static method for adding cutom protocol   * handlers without getting bogged down with other class loaders and having to   * call setURLStreamHandlerFactory before the next guy...   */  package com.cybernostics.lib.net.customurl;    import java.net.URLStreamHandler;  import java.util.regex.Matcher;  import java.util.regex.Pattern;    /**   * Allows you to add your own URL handler without running into problems   * of race conditions with setURLStream handler.   *    * To add your custom protocol eg myprot://blahblah:   *    * 1) Create a new protocol package which ends in myprot eg com.myfirm.protocols.myprot   * 2) Create a subclass of URLStreamHandler called Handler in this package   * 3) Before you use the protocol, call CustomURLScheme.add(com.myfirm.protocols.myprot.Handler.class);   * @author jasonw   */  public class CustomURLScheme  {        // this is the package name required to implelent a Handler class      private static Pattern packagePattern = Pattern.compile( "(.+\\.protocols)\\.[^\\.]+" );        /**       * Call this method with your handlerclass       * @param handlerClass       * @throws Exception        */      public static void add( Class<? extends URLStreamHandler> handlerClass ) throws Exception      {          if ( handlerClass.getSimpleName().equals( "Handler" ) )          {              String pkgName = handlerClass.getPackage().getName();              Matcher m = packagePattern.matcher( pkgName );                if ( m.matches() )              {                  String protocolPackage = m.group( 1 );                  add( protocolPackage );              }              else              {                  throw new CustomURLHandlerException( "Your Handler class package must end in 'protocols.yourprotocolname' eg com.somefirm.blah.protocols.yourprotocol" );              }            }          else          {              throw new CustomURLHandlerException( "Your handler class must be called 'Handler'" );          }      }        private static void add( String handlerPackage )      {          // this property controls where java looks for          // stream handlers - always uses current value.          final String key = "java.protocol.handler.pkgs";            String newValue = handlerPackage;          if ( System.getProperty( key ) != null )          {              final String previousValue = System.getProperty( key );              newValue += "|" + previousValue;          }          System.setProperty( key, newValue );      }  }      CustomURLHandlerException.java:  /*   * Exception if you get things mixed up creating a custom url protocol   */  package com.cybernostics.lib.net.customurl;    /**   *   * @author jasonw   */  public class CustomURLHandlerException extends Exception  {        public CustomURLHandlerException(String msg )      {          super( msg );      }    }  


(Similar to Azder's answer, but a slightly different tact.)

I don't believe there is a predefined protocol handler for content from the classpath. (The so-called classpath: protocol).

However, Java does allow you to add your own protocols. This is done through providing concrete implementations java.net.URLStreamHandler and java.net.URLConnection.

This article describes how a custom stream handler can be implemented: http://java.sun.com/developer/onlineTraining/protocolhandlers/.


Solution with registering URLStreamHandlers is most correct, of course, but sometimes the simplest solution is needed. So, I use the following method for that:

/**   * Opens a local file or remote resource represented by given path.   * Supports protocols:   * <ul>   * <li>"file": file:///path/to/file/in/filesystem</li>   * <li>"http" or "https": http://host/path/to/resource - gzipped resources are supported also</li>   * <li>"classpath": classpath:path/to/resource</li>   * </ul>   *   * @param path An URI-formatted path that points to resource to be loaded   * @return Appropriate implementation of {@link InputStream}   * @throws IOException in any case is stream cannot be opened   */  public static InputStream getInputStreamFromPath(String path) throws IOException {      InputStream is;      String protocol = path.replaceFirst("^(\\w+):.+$", "$1").toLowerCase();      switch (protocol) {          case "http":          case "https":              HttpURLConnection connection = (HttpURLConnection) new URL(path).openConnection();              int code = connection.getResponseCode();              if (code >= 400) throw new IOException("Server returned error code #" + code);              is = connection.getInputStream();              String contentEncoding = connection.getContentEncoding();              if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip"))                  is = new GZIPInputStream(is);              break;          case "file":              is = new URL(path).openStream();              break;          case "classpath":              is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path.replaceFirst("^\\w+:", ""));              break;          default:              throw new IOException("Missed or unsupported protocol in path '" + path + "'");      }      return is;  }  


An extension to Dilums's answer:

Without changing code, you likely need pursue custom implementations of URL related interfaces as Dilum recommends. To simplify things for you, I can recommend looking at the source for Spring Framework's Resources. While the code is not in the form of a stream handler, it has been designed to do exactly what you are looking to do and is under the ASL 2.0 license, making it friendly enough for re-use in your code with due credit.


Inspire by @Stephen https://stackoverflow.com/a/1769454/980442 and http://docstore.mik.ua/orelly/java/exp/ch09_06.htm

To use

new URL("classpath:org/my/package/resource.extension").openConnection()  

just create this class into sun.net.www.protocol.classpath package and run it into Oracle JVM implementation to work like a charm.

package sun.net.www.protocol.classpath;    import java.io.IOException;  import java.net.URL;  import java.net.URLConnection;  import java.net.URLStreamHandler;    public class Handler extends URLStreamHandler {        @Override      protected URLConnection openConnection(URL u) throws IOException {          return Thread.currentThread().getContextClassLoader().getResource(u.getPath()).openConnection();      }  }  

In case you are using another JVM implementation set the java.protocol.handler.pkgs=sun.net.www.protocol system property.

FYI: http://docs.oracle.com/javase/7/docs/api/java/net/URL.html#URL(java.lang.String,%20java.lang.String,%20int,%20java.lang.String)


I dont know if there is one already, but you can make it yourself easilly.

That different protocols example looks to me like a facade pattern. You have a common interface when there are different implementations for each case.

You could use the same principle, make a ResourceLoader class which takes the string from your properties file, and checks for a custom protocol of ours

myprotocol:a.xml  myprotocol:file:///tmp.txt  myprotocol:  myprotocol:jar:http://www.foo.com/bar/baz.jar!/COM/foo/Quux.class  

strips the myprotocol: from the start of the string and then makes a decision of which way to load the resource, and just gives you the resource.


I try to avoid the URL class and instead rely on URI. Thus for things that need URL where I would like to do Spring Resource like lookup with out Spring I do the following:

public static URL toURL(URI u, ClassLoader loader) throws MalformedURLException {      if ("classpath".equals(u.getScheme())) {          String path = u.getPath();          if (path.startsWith("/")){              path = path.substring("/".length());          }          return loader.getResource(path);      }      else if (u.getScheme() == null && u.getPath() != null) {          //Assume that its a file.          return new File(u.getPath()).toURI().toURL();      }      else {          return u.toURL();      }  }  

To create a URI you can use URI.create(..). This way is also better because you control the ClassLoader that will do the resource lookup.

I noticed some other answers trying to parse the URL as a String to detect the scheme. I think its better to pass around URI and use it to parse instead.

I have actually filed an issue a while ago with Spring Source begging them to separate out their Resource code from core so that you don't need all the other Spring stuff.


In a Spring Boot app, I used the following to get the file URL,


Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Next Post »