2

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.

Doenerstyle
  • 21
  • 2
  • 5
  • 1
    Why do you want to get the path of the JAR? – SJuan76 Jun 19 '16 at 00:13
  • 1
    `getPath()` *does not* convert a URI to a file. Even if it’s a file: URI, the path portion may contain percent-escapes, so using getPath() will eventually return a string which is not a valid file name. The correct way to convert a URI to a file name is `Paths.get(uri)`, but it only works with file: URIs. That said, whatever you’re trying to do probably can and should be done using Class.getResource or ClassLoader.getResource. – VGR Jun 19 '16 at 01:47
  • you can get a path to the jar itself, but it makes no sense to talk about a file path to a file in the jar. – MeBigFatGuy Jun 19 '16 at 02:16
  • @SJuan76 I want to copy some files and folders that are inside the JAR to the JARs directory. That works if I just type in "D:\example\example.jar", but the path is not always the same. – Doenerstyle Jun 19 '16 at 14:55
  • @VGR And how do I use Class(Loader).getResource() to find out the JARs path? – Doenerstyle Jun 19 '16 at 15:03
  • @MeBigFatGuy I need to get the currently running JAR file as JarFile to read out its JarEntries. Like this: `JarFile file = new JarFile(new File("D:\example\example.jar"))` But I can't just type in the JARs path because it may change. – Doenerstyle Jun 19 '16 at 15:07

5 Answers5

11

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;
    }

}
GreenThor
  • 456
  • 5
  • 14
0

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.

VGR
  • 40,506
  • 4
  • 48
  • 63
  • I have a working method to copy these folders and files, I just need the path of my JAR file to read out its entries. I can't use your method because there are too many files to type in their paths by hand. – Doenerstyle Jun 20 '16 at 18:11
  • Why not open a terminal window or command window, enter a command like `dir /b` (in Windows) or `ls -1` (other OSes), then copy and paste the output into your code, where you can format it as an array of Strings? You could also execute `jar tf` on your .jar file after building. – VGR Jun 20 '16 at 20:58
0
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();
            }
        }
    }

}
MeBigFatGuy
  • 28,272
  • 7
  • 61
  • 66
0

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!

Doenerstyle
  • 21
  • 2
  • 5
0

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));
j-hap
  • 150
  • 1
  • 2
  • 9