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.
# 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.
# 3
You can build a stack trace (inside a throwable object) and examine it.
# 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() );
}
}
# 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();
}
}
# 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;
}
}
# 7
Nice try, but it still doesn't work. Try running the example I posted.
# 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.
# 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).
# 10
I am sorry I overlooked that and the proposed solution is not waterproof.
# 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 ();
}
}
# 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.
# 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
