40

I've created an executable jar and using commons-cli to give the user the ability to specify command line parameters when he launches the client. Everything works fine. However, when I print the usage statement for the jar, I would like to show the following:

usage: java -jar myprog.jar <options> <file>
--help Display the help message
--debug Enable debugging
....

Printing of all the options is easily done with commons-cli. However, the "usage" line is the head scratcher. I cannot seem to figure out a way to get the "myprog.jar" name from the args[] that are passed to the application.

Is there any easy way of doing this? I could use a pretty convoluted method to back trace from my class' classloader and figure out if it is contained within a jar, but that seems like a fairly ugly answer to what should be a pretty simple question.

private String getPath(Class cls) {
    String cn = cls.getName();
    String rn = cn.replace('.', '/') + ".class";
    String path =
            getClass().getClassLoader().getResource(rn).getPath();
    int ix = path.indexOf("!");
    if(ix >= 0) {
        return path.substring(0, ix);
    } else {
        return path;
    }
}
Eric B.
  • 23,425
  • 50
  • 169
  • 316
  • tried http://stackoverflow.com/questions/320542/how-to-get-the-path-of-a-running-jar-file?lq=1 ? – Charles Jun 22 '12 at 14:43
  • I did see that link already, but it looked as though it was almost a "hack" as well. I cannot believe that there is not a more direct solution. Additionally, the API states that "getCodeSource()" may return null, but does not elaborate under which conditions, so I naturally wondered if this was a "fail-safe" method to use. – Eric B. Jun 22 '12 at 15:03

2 Answers2

62

Here you go:

new java.io.File(SomeClassInYourJar.class.getProtectionDomain()
  .getCodeSource()
  .getLocation()
  .getPath())
.getName()

Edit: I saw your comment about getSourceCode API. Well, this is probably the best you can do in Java. About getCodeSource() returning null, I think it mainly happens on classes in java.lang.* and other special classes for which the source location is "hidden". Should work for your own classes though.

rodion
  • 14,729
  • 3
  • 53
  • 55
  • 1
    Thanks - that's the same thing that @Charles pointed to in the SO link. My biggest concern as I mentioned above is that the api for `getCodeSource()` indicates that it can be null, but does not elaborate under which conditions. – Eric B. Jun 22 '12 at 15:42
  • The other problem with this is that it does not take into account the fact that the class file may be nested within archives. So I would still need to check for a `!` substring. Like I said, it seems a little clunky and am quite surprised that Java does not have a better solution. – Eric B. Jun 22 '12 at 18:05
  • It's mostly because there is rarely a reason to know the name of the jar file you're running from. The functionality should (ideally) be independent of the name. – Charles Jun 22 '12 at 19:22
  • @rodion for me the above is giving classes! as output – saravana kumar ramasamy Aug 19 '22 at 10:22
  • Any idea if this technique will translate to GraalVM AOTC? I'd like to create a multicall binary. – Sridhar Sarnobat Nov 05 '22 at 17:24
2

You should in any case add a .toURI() before you call getPath(). Thats because of some quirks in java's URL implementation - see how to encode URL to avoid special characters in java for details.

Community
  • 1
  • 1
Michael Wyraz
  • 3,638
  • 1
  • 27
  • 25