views:

557

answers:

5

I want to determine the class name where my application started, the one with the main() method, at runtime, but I'm in another thread and my stacktrace doesn't go all the way back to the original class.

I've searched System properties and everything that ClassLoader has to offer and come up with nothing. Is this information just not available?

Thanks.

+2  A: 

Try using Thread.getAllStackTraces(). It returns a Map of the stack traces from all running threads, not just the current one.

Bill the Lizard
That doesn't really help, since the thread that initially ran the main class need not be running any more.
Joachim Sauer
(Doesn't help in every conceivable case) != (doesn't help at all).
Bill the Lizard
I agree and realized that after posting the comment. Still it's good to be aware of the limits of a solution.
Joachim Sauer
No hard feelings. :) After reading the revised question and several comments on other answers I realize this isn't going to solve the OP's problem. Still, I think it might be helpful to other people going down the same path.
Bill the Lizard
A: 

How about something like:

Map<Thread,StackTraceElement[]> stackTraceMap = Thread.getAllStackTraces();
for (Thread t : stackTraceMap.keySet())
{
 if ("main".equals(t.getName()))
 {
  StackTraceElement[] mainStackTrace = stackTraceMap.get(t);
  for (StackTraceElement element : mainStackTrace)
  {
   System.out.println(element);
  }
 }
}

This will give you something like

java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:231)
java.lang.Thread.join(Thread.java:680)
com.mypackage.Runner.main(Runner.java:10)

The main thread is probably not guarenteed to be called "main" though - might be better to check for a stack trace element that contains (main

Edit if the main thread has exited, this is no good!

Harry Lime
I've tried this. It's not in my stack. This was my first guess, too.
Erik R.
I added an edit as you posted this comment. If the thread doesn't exist anymore, I'm not sure there's much that can be done
Harry Lime
+1  A: 

I figured it out. Can anyone tell me if this environment variable will always be around in other java implementations across operating systems?

public static String getMainClassName()
{
  for(final Map.Entry<String, String> entry : System.getenv().entrySet())
  {
    if(entry.getKey().startsWith("JAVA_MAIN_CLASS"))
      return entry.getValue();
  }
  throw new IllegalStateException("Cannot determine main class.")
}
Erik R.
Why not simply System.getenv("JAVA_MAIN_CLASS")?
Michael Myers
Mine had a number (pid?) tacked onto the end of the key. e.g. "JAVA_MAIN_CLASS_13833" Hence the startsWith().
Erik R.
That's not available on IBM 1.5.0 JRE, which I'm using
Harry Lime
for IBM it is available in IBM_JAVA_COMMAND_LINED though, but you'd have to parse the string. This is exactly what's in the value: D:\path-to\javaw.exe -classpath D:\workspace\bin com.mypackage.Runner
Harry Lime
Is that your IDE doing that?
Tom Hawtin - tackline
This might work but it's not portable between JVMs.
Aaron Digulla
@Tom you're right it's the IDE. Either way it can't be relied upon I guess
Harry Lime
+1  A: 

Given the clarification, I suggest using "Parameterisation from Above". You have the information to start with, keep hold of it.

I did put in an RFE 4827318 (six years ago!) for something like this for use with test runners.

Tom Hawtin - tackline
A: 

I suggest to put this information into a system property. This is usually simple to do when you start your application from a script.

If you can't do that, I suggest to set the property in the main() method of every application. The most simple way here would be to have every app derive it's "main class" from a common base class and run an init step in there. I often do this for command line processing:

public class Demo extends Main {
    main(String[] args) {
        Main._main(new Demo (), args);
    }

    // This gets called by Main._main()
    public void run (String[] args) {
    }
}
Aaron Digulla