Search code examples
javamavenjarresourcesclassloader

Equivalent of this.getClass().getClassLoader().getResource(".").toURI() from within a Jar


I'm trying to achieve a way to obtain the base path of the current classloader when runnning from within a jar.

I mean programatically, I already know it should have the shape of "jarPath+jarFile.jar!/"

Unlike file system's call, getResource(".") or .getResource("/") do not work from inside the jar.

Ideally it should be an abstract solution for any file provider, so something like:

Path BASE_PATH = Paths.get(...getResource("").toURI())

which could return the correct root path for both jars and file system so I can use relative urls to my resources without having to do any conditional statements and url manual string parsing/build.


Solution

  • You should be able to find out the path of the jar and or target folder containing you class or any resource by using this code:

    package com.stackoverflow.test;
    
    import java.net.URL;
    import java.nio.file.Paths;
    
    public class ClassPathUtils {
    
      public static String getBasePath(String jarPath) {
        String path = getJarPathFromClass(jarPath);
        if (path == null) {
          return null;
        }
    
        if (path.startsWith("jar:")) {
          path = path.substring("jar:".length());
        }
        if (path.startsWith("file:")) {
          path = path.substring("file:".length());
        }
        if (path.endsWith(jarPath)) {
          path = path.substring(0, path.length()-jarPath.length());
        }
    
        return path;
      }
      public static String getBasePath(Class clazz) {
        return getBasePath(classNameDotClass(clazz));
      }
      private static String classNameDotClass(Class clazz) {
        return clazz.getName().replaceAll("\\.", "/") + ".class";
      }
      private static String getJarPathFromClass(String resource) {
        final URL url = ClassPathUtils.class.getClassLoader().getResource(resource);
        return url == null ? null : url.toString();
      }
      public static void main(String[] args) {
        //System.out.println(Paths.get(ClassPathUtils.getBasePath("."))); // doesn't work in a jar
        System.out.println(Paths.get(ClassPathUtils.getBasePath(ClassPathUtils.class)));
    
        System.out.println(Paths.get(ClassPathUtils.getBasePath("fonts/atcitadelscript.ttf"))); // any classpath resource
    
        System.out.println(Paths.get(ClassPathUtils.getBasePath(String.class))); // actually finds rt.jar
    
      }
    }
    

    If you run this code from your IDE, or from maven, it will give you the paths to target/classes for your own resources, or the path to a jar for other resources (E.g. String.class). If you call it from a jar, it will always tell you the path of the jar file.

    run from IDE:

    /home/alexander/projects/stackoverflow/stuff/target/classes
    /home/alexander/projects/stackoverflow/stuff/target/classes
    /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar!`
    

    run from JAR:

    /home/alexander/projects/stackoverflow/stuff/target/test-stuff-0.1-SNAPSHOT.jar!
    /home/alexander/projects/stackoverflow/stuff/target/test-stuff-0.1-SNAPSHOT.jar!
    /usr/lib/jvm/java-7-openjdk-amd64/jre/lib/rt.jar!
    

    Is that what you're looking for?