How to find main class name?

Let's say I runjava com.mybiz.SimpleTest

How can I find out from within my Java program the name of the class on the command line? That is, how can I write a methodpublicstatic String getMainClassName(){

// What goes here?

}

that will returncom.mybiz.SimpleTest

in my example?

I tried:

1) Looking in the system properties

- It's not there

2) Creating a stack trace and parsing it

- Obviously this only works from the main thread, and even then it fails in some cases

3) Using ManagementFactory.getRuntimeMXBean().getInputArguments()

- This just gives the VM arguments, not the main class name: and I need to give special command-line arguments on JDK 5 (OK on JDK 6).

Any other ideas? How come this information is available to other processes (e.g. jps) but not my own? Do I have to drop down into JNI? Or am I missing something really obvious? Or something cunning?

Thanks,

R

[1126 byte] By [RGibsona] at [2007-11-26 15:01:37]
# 1

Executing a class from the command line requires that the class name be the same as the file name - so when you write the code for that class you know it.

Maybe you want a random class to know what class started an application? In the initial class you could write the classname to a property and then retrieve it later.

ChuckBinga at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 2

Well I could set a system property, like you say, from the command line or in my main class, but this requires that I remember to do it and is a bit fragile. I was hoping there would be something equivalent to $0 in shell (for example) that requires no changes to my client code to set up: and in "client code" I include my scripts to launch my applications, of which I have quite a few, unfortunately.

RGibsona at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 3
You can build a stack trace (inside a throwable object) and examine it.
BIJ001a at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 4

public class s

{

static String tell()

{

Exceptione = new Exception();

StackTraceElement[] em = e.getStackTrace();

return em[ em.length - 1 ].getClassName();

}

}

public class t

{

public static void main( String a[] )

{

System.out.print( s.tell() );

}

}

BIJ001a at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 5

Creating a stack doesn't work in certain cases that I'm interested in: public class Superclass {

static {

System.out.println(tell()); // Doesn't work

}

public static String tell() {

Exceptione = new Exception();

StackTraceElement[] em = e.getStackTrace();

return em[ em.length - 1 ].getClassName();

}

}

public class Subclass extends Superclass {

public static void main(String... args) {

System.out.println (tell()); // Works

new Thread(new Runnable() {

public void run() {

System.out.println (Superclass.tell()); // Doesn't work

}

}).start();

}

}

RGibsona at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 6

public class Teller

{

public static String tell()

{

Exceptione = new Exception();

StackTraceElement[] em = e.getStackTrace();

for ( int i = em.length - 1; i >= 0; i-- )

{

Stringret = em[ i ].getClassName();

if ( !ret.startsWith( "java.lang" ) )

{

return ret;

}

}

return null;

}

}

BIJ001a at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 7
Nice try, but it still doesn't work. Try running the example I posted.
RGibsona at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 8
I provided the idea (including to use some heuristics to avoid the java core library classes to find the user-supplied one), working out the details is left as an excercise to the reader.
BIJ001a at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 9
Thanks for your idea, but I don't think there's any way to get it to work in the general case (and if you look at my original post you'll see that I had already tried it, as solution 2).
RGibsona at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 10
I am sorry I overlooked that and the proposed solution is not waterproof.
BIJ001a at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 11

In 1.5 put tools.jar in you path and try

mport java.lang.management.*;

import java.lang.instrument.*;

import java.util.*;

import javax.management.*;

import sun.jvmstat.monitor.*;

public class JPS {

public static void main (String[] args) {

try {

MonitoredHost localhost = MonitoredHost.getMonitoredHost("localhost");

Set ids = new TreeSet(localhost.activeVms());

for (Object id : ids) {

MonitoredVm vm = localhost.getMonitoredVm (new VmIdentifier ("//" + id));

String name = MonitoredVmUtil.mainClass (vm, false);

System.err.println (id + "\t" + name);

}

} catch (Exception e) {

e.printStackTrace ();

}

}

donncha0a at 2007-7-8 8:50:34 > top of Java-index,Core,Monitoring & Management...
# 12
Did you try using java.lang.Thread.getAllStackTraces()? It can dumpstack trace element of all threads. You can also get this information from JVMTI and JDI. For JVMTIyou need to write code in C or C++. And jdi is an external processapi.
swamyva at 2007-7-8 8:50:35 > top of Java-index,Core,Monitoring & Management...
# 13

Thanks to donncha0 I found this post

http://elliotth.blogspot.com/2005/01/java-equivalent-of-heap1.html

and my code so far looks like this

public static String getMainClassName ()

throws MonitorException, URISyntaxException

{

RuntimeMXBean rBean = ManagementFactory.getRuntimeMXBean ();

Matcher m = Pattern.compile ("(\\d*)@.*").matcher (rBean.getName ());

if (!m.matches ()) throw new MonitorException ("Strange name: " + rBean.getName ());

String id = m.group (1);

MonitoredHost localhost = MonitoredHost.getMonitoredHost ("localhost");

MonitoredVm vm = localhost.getMonitoredVm (new VmIdentifier ("//" + id));

String name = MonitoredVmUtil.mainClass (vm, true);

return name;

}

The only problems are:

1) It uses undocumented APIs

2) It relies on the specific format of the "name" string in the Runtime MXBean

3) I need to put tools.jar in my classpath

4) Under JDK1.5 I need to add command-line arguments

So it might work today, but the odds of it working in 6 months time are rather low ... any takers to improve it (and I'd rather not have to make any changes to my classpath or change input parameters)?

R

RGibsona at 2007-7-8 8:50:35 > top of Java-index,Core,Monitoring & Management...