Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

C argv[0] equivalent for Java

In C, you can get the name of the binary file called from the shell with argv[0]. In Java, it seems there is no obvious way to get the equivalent: the name of the class that has the entry-point main() class.

I made three options, but none of them are fully portable.

1: Specify it explicitly in the class

package com.example;

public class Foo {
    public static void main(String[] args) {
        System.out.println(Foo.class.getName());
    }
}
  • pros: Most straightforward way. No tricky code.
  • cons 1: You can use this only in the "main" class. You have to specify the class object for each class and cannot simply copy and paste the code.
  • cons 2: You have to pass the name from the "main" class. You cannot use this option for the logic that runs before the main class. For example, you cannot use this in PropertyDefiner of Logback when you run the main class from mvn test (PropertyDefiner runs earlier than the "main" class).

2: See the bottom of the call stack

package com.example;

public class Foo {
    public static void main(String[] args) {
        Bar b = new Bar();
        b.start();

        StackTraceElement [] st = Thread.currentThread().getStackTrace();
        System.out.println("Foo: " + st[st.length-1].getClassName());  // com.example.Foo

        Baz z = new Baz();
        z.baz();
    }
}

class Bar extends Thread {
    public void run() {
        StackTraceElement [] st = Thread.currentThread().getStackTrace();
        System.out.println("Bar: " + st[st.length-1].getClassName());  // com.example.Bar
    }
}

class Baz {
    public void baz() {
        StackTraceElement [] st = Thread.currentThread().getStackTrace();
        System.out.println("Baz: " + st[st.length-1].getClassName());  // com.example.Foo
    }
}
  • pros: You can use this anywhere in the code.
  • cons 1: You will get the wrong class name when you use threads.
  • cons 2: It could be slow if the call stack is too deep.
  • cons 3: The result could not be the name of the "main" class according to how to launch the application. When you run the application from a Spring executable jar (java -jar foo.jar), the result could be org.springframework.boot.loader.JarLauncher. When you run the application from mvn test, the result could be org.apache.maven.surefire.booter.ForkedBooter.

3: See the system property

package com.example;

public class Foo {
    public static void main(String[] args) {
        System.out.println(System.getProperty("sun.java.command").split("\\s")[0]);
    }
}
  • pros: You can use this anywhere in the code even if you use threads.
  • cons 1: This system property is not explicitly defined in any document (it seems defined in OpenJDK and OpenJ9).
  • cons 2: The result could not be the name of the "main" class according to how to launch the application. When you run the application from a Spring executable jar (java -jar foo.jar), the result could be the relative path of the jar file. When you run the application from mvn package, the result could be the absolute path of the temporary jar file.