argv[0] for Java

I’m happy with Java. There, I said it. I mean, I noodle around in Python, have done Rails, recently looked at Scala, but mostly there is little I can’t get done in Java. Mostly that is a side-effect of using Java for a long time; I went to a seminar at the University of Maryland sometime in 1996-97, with my copy of Java in a Nutshell clenched in my hand, and listened to a guy give a talk in Java. He said something along the lines of “Look, Java has some neat ideas, and we’re going to explore them today. But no one is going to write real applications in it.”

Ha. Still, things have come a long way since that 1.0 JDK. HotJava. What’s an Interface? The awful AWT. Greenthreads, by gum!

Since then, I’ve been lucky to have a succession of jobs where I’ve worked on non-gui Java codebase’s. Telemetry systems, compilers, logic engines, etc.

Since Java is my hammer, I’ve evolved some tricks. One of my favorites involves argv[0] for Java.

In C, argv[] is the array of command-line arguments to a program. For example, for the invocation:

tail foo.txt bar.txt

argv[1] would be “foo.txt”, and argv[2] would be “bar.txt”.

More interestingly, the convention is that argv[0] would equal the complete path name of the program being run, in this case /usr/bin/tail.

This is useful for all sorts of reasons; for example, you can use that to find the location of the invoked program (/usr/bin in this case).

This bugged me for a long time with Java; if I had a utility in a jar file, and I invoked it via a script like:

java -jar ~/lib/foo.jar

I couldn’t find my way home to the location where foo.jar lived on the file system; I wanted argv[0] for Java. Annoying.

Annoy a software guy, and you get a solution, right?

So, my solution:

package com.designbygravity.utils;

import java.io.*;
import java.net.*;

public class ArgvZero
{
	/**
	 * The idea here is to find a root directory via a specific class. If the package
	 * is in a jar, the on-disk location of the jar is returned. If the class file
	 * exists on disk directly, either the actual location of the class file or 
	 * the class's package root directory is returned. 
	 * 
	 * This let's you take a class as your root, through it in with a whole application
	 * in a jar, and then find the directory the jar resides in no matter where the 
	 * application was run from.
	 * 
	 * The idea is to give some functionality like C's argv[0], which is often used
	 * for just that purpose when writing little utils and such.
	 * 
	 * @param clazz Class to use as the location anchor
	 * @param findRootOfPackage Whether to return the package root for a .class file
	 * 
	 * @throws UnsupportedEncodingException
	 * @throws URISyntaxException
	 */
	
	public static File findHome(Class clazz,boolean findRootOfPackage) throws UnsupportedEncodingException, URISyntaxException
	{
		// get the resource url and path. Closest thing we have to physical location
		URL url = clazz.getResource(clazz.getSimpleName() + ".class");
		String urlPath = url.getPath();

		if (url.getProtocol().equals("file"))
		{
			// decode it and get the parent
			File homeLocation = new File(URLDecoder.decode(urlPath, "UTF-8")).getParentFile();
			
			// if we should unwind the package to the classpath root.
			if(findRootOfPackage)
			{
				// get the package
				Package p = clazz.getPackage();
	
				if (p != null)
				{
					// work your way up as many times as the target class has packes
					// so package com.foo.bar will move up 3 levels in the directory
					String[] arrs = p.getName().split("[.]");
					for (int i = 0; i = 0)
			{
				// kill the stuff after the end of the jar file name
				urlPath = urlPath.substring(0, pos);
			}

			// create a new uri, get path, make file from it
			URI uri = new URI(urlPath);
			urlPath = uri.getPath();
			File homeLocation = new File(URLDecoder.decode(urlPath, "UTF-8")).getParentFile();
			
			return homeLocation;
		}
		else
		{
			return null;
		}
	}

	public static void main(String[] args) throws UnsupportedEncodingException, URISyntaxException
	{
		File f;

		f = ArgvZero.findHome(String.class,true);
		System.out.println(f);
		
		f = ArgvZero.findHome(ArgvZero.class,false);
		System.out.println(f);

		f = ArgvZero.findHome(ArgvZero.class,true);
		System.out.println(f);

	}
}

So, what does this do? Basically, for a class that is loadable, it attempts to find the physical location of either the .class file itself, or the .jar file the .class file is contained in.

Usage is pretty simple; look at the main program for example usage. You can use any class you can load, and you have one decision to make. If the class file is located in a jar file, you get the directory the jar file is located in. If the .class file is on the filesystem, you have a choice, as to whether you want the location of the .class file itself, or the location of the of the root of the package of the .class file. I’ve used it both ways; your choice.

On my Windows partition, running the class file produces:

C:\Program Files\Java\jdk1.6.0_16\jre\lib
C:\ws\pers\Pers\bin\com\designbygravity\utils
C:\ws\pers\Pers\bin

Enjoy.

P.S. Yes, this doesn’t give you argv[0]‘s capability of knowing the name of the invoked program, a favorite trick in the land of symbolic links and such.

About these ads
Explore posts in the same categories: Software, Tech

Tags: ,

You can comment below, or link to this permanent URL from your own site.

9 Comments on “argv[0] for Java”

  1. Alex Miller Says:

    Another way to this is with Foo.class.getProtectionDomain().getCodeSource().

    If you want to know more externally, the good old jps command can tell you lots of useful info.

    • designbygravity Says:

      Yeah, that’s true. However, I had varying luck with it under early linux JDK’s; hence the above solution, which I’ve not had fail me in years. But in the days of Java 5 being EOL’d (which some of customers seem happy to ignore), it probably is a good way to go.

  2. sedwards Says:

    Hey, what’s with all the comments? ;-)


  3. Do you mind if I quote a few of your posts as long as I provide
    credit and sources back to your website? My blog is in the very same niche as yours
    and my users would truly benefit from some of the information you provide here.
    Please let me know if this alright with you. Thank you!

  4. Gay Says:

    great submit, very informative. I ponder why the opposite experts of this sector do
    not understand this. You should proceed your writing. I am confident, you’ve a huge readers’ base already!


  5. I’ll right away grab your rss as I can’t to find your email subscription link or e-newsletter service.

    Do you have any? Kindly allow me realize in order that I may just
    subscribe. Thanks.

  6. Rudolf Says:

    Hi there very cool website!! Guy .. Beautiful
    .. Amazing .. I’ll bookmark your website and take the feeds additionally? I’m happy to search
    out numerous helpful information right here in the submit,
    we need develop extra techniques on this regard, thank you
    for sharing. . . . . .


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s


Follow

Get every new post delivered to your Inbox.

%d bloggers like this: