Getting the path of a running JAR file returns "rsrc:./"

4.5k Views Asked by At

My code runs inside a JAR file and I need to get the full path of that file. For example, my JAR is called example.jar and is located at D:\example\ So I need to get "D:\example\example.jar" by some code inside that jar. I have tried many methods to get that path, but none of them worked correctly.

One of them is

getClass().getProtectionDomain().getCodeSource().getLocation().toURI().getPath()

Many people say that this works for them, but it returns "rsrc:./" for me.

I have searched after that and I noticed that my MANIFEST.MF contains this:

Manifest-Version: 1.0
Rsrc-Class-Path: ./
Class-Path: .
Rsrc-Main-Class: Example
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader

I don't know what that means, but if I remove that Rsrc stuff and replace the other things with it, it says the jar is broken. I think this is the reason why it doesn't work. Does anybody know what this means?

PS: I'm running my JAR using a BAT file.

5

There are 5 best solutions below

0
On BEST ANSWER

I just have created a new workspace and moved every project into it and everything works fine now, I think it was a bug or something...Thank you all for your help!

2
On

Based on your comments, it appears your real question is how to copy files from inside your application .jar. You can do that with something like this:

String jarEntry = "/files/data.txt";
Path destination = Paths.get(
    System.getProperty("user.home"), "Downloads", "data.txt");

try (InputStream stream = getClass().getResourceAsStream(jarEntry)) {
    Files.copy(stream, destination);
}

Class.getResource and Class.getResourceAsStream read data from the classpath, usually as an entry in a .jar file that is on the classpath, such as your own application’s .jar file.

A file embedded in the classpath is normally called an application resource or just “resource” for short. Resources are always specified using the forward slash (/) as a directory separator, on all platforms, even Windows.

If you are not sure what string you should pass to getResource or getResourceAsStream, examine the contents of your .jar file.

3
On
package com.example;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public class HomeJar {

    public static void main(String[] args) throws IOException {

        URL u = HomeJar.class.getProtectionDomain().getCodeSource().getLocation();

        File f = new File(u.getPath().toString());

        if (!f.isFile()) {
            throw new RuntimeException("'" + u + "' isn't a jar");
        }

        try (JarInputStream jis = new JarInputStream(new BufferedInputStream(new FileInputStream(f)))) {
            JarEntry je = jis.getNextJarEntry();
            while (je != null) {
                System.out.println(je.getName());
                je = jis.getNextJarEntry();
            }
        }
    }

}
0
On

This was the exact problem I had today. I finally found this: To get the jar-file location when packaging with eclipses Package required libraries into generated JAR one can use this (insert name of the calling class in the <>:

var thisClassesResourcePath = <CLASSNAME>.class.getName().replace('.', '/') + ".class";
var resource = ClassLoader.getSystemResource(thisClassesResourcePath);
var path = resource.getPath();
var jarUrl = new URL(path.substring(0, path.lastIndexOf("jar!") + 3));
1
On

I stumbled over this problem too and leave my investigations here for people who ask themselves in the future what the rsrc means.

I'm using Eclipse Mars 1 and try to export my project as a runnable JAR. There I can choose the library handling and decide between:

  1. Extract required libraries into generated JAR
  2. Package required libraries into generated JAR
  3. Copy required libraries into a sub-folder next to the generated JAR

The line to be tested is

System.out.println(MyClass.class.getProtectionDomain().getCodeSource().getLocation());

the JAR file's name is MyJar.jar (which will be put on desktop), Project's name and folder is MyProject.

Results:

  1. file:/C:/Users/admin/Desktop/MyJar.jar
  2. rsrc:./
  3. file:/C:/Users/admin/Desktop/MyJar.jar
  4. <means running in Eclipse> file:/C:/Development/workspace/MyProject/target/classes/

I wrote a convinience method for that:

public class SystemUtils {

    /**
     * Let no one instanciate this class.
     */
    private SystemUtils() {}

    /**
     * If the current JVM was started from within a JAR file. 
     * @return <code>Boolean.TRUE</code> if it is, <code>Boolean.FALSE</code> if it is not, <code>null</code> if unknown.
     */
    public static Boolean executedFromWithinJar() {
        Boolean withinJar = null;
        try {
            String location = SystemUtils.class.getProtectionDomain().getCodeSource().getLocation().toString();
            if (location.startsWith("rsrc:")
                || location.endsWith(".jar") && !new File(location.substring(location.indexOf(':') + 1)).isDirectory())
                withinJar = Boolean.TRUE;
            else
                withinJar = Boolean.FALSE;
        }
        catch (Exception ex) {/* value is still null */}
        return withinJar;
    }

}