views:

92

answers:

3

Hello,

I have found following question: http://stackoverflow.com/questions/41894/0-program-name-in-java-discover-main-class but accepted answer fails in this situation:

public class Derived extends Base { }

class Base {
    public static void main(String[] args){
        System.out.println(getTheClassName());
    }

    static String getTheClassName(){
        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
        StackTraceElement main = stack[stack.length - 1];
        return main.getClassName();
    }
}

When calling:

java Derived

the output is unfortunately Base not Derived as expected.

Is it possible to get the name of real main class? (btw. jps tool detects main class correctly but to get the proper name I need to know ID of current VM, and that is also a problem)

Best regards.

Edit: to be precise: I need to know what is the name of class passed as command line argument passed to JVM. jps tools does it the way I want, but I cannot use this tool because of other problems (such as unknown VMid).

Edit2: replying globally to Thorbjørn's answer:

For your approach to work, you need to have a non-static method instead. Make it non-static, have a main() in Derived doing a new Derived().getTheClassName()

I am wondering I can get the name without implementing main method in Derived class.

Solution: I will provide both (Thorbjørn's and erickson's) mechanisms of an initialization of Derived class ;-) All of the answers were very helpful. I accepted Thorbjørn's becase he posted his answer earlier than erickson. Thank You.

+3  A: 

Why would you expect Derived when the main entry-point is in Base? Members that are declared static belong to their class and are not inherited. When running the program as is, the class Derived will not even be loaded, as it is never referenced.


Consider taking the derived class's name as an argument to the Base class. In addition to making the target class explicit, it might be a convenient place to implement other features.

class Base {
  public static void main(String... argv) throws Exception {
    Class<?> clz = Class.forName(argv[0]);
    Method mth = clz.getMethod("main", String[].class);
    String[] sub = new String[argv.length - 1];
    System.arraycopy(argv, 1, sub, 0, sub.length);
    mth.invoke(null, sub);
  }
}
erickson
I expect `Derived`, because as I said, `jps` tools prints `Derived` to the `stdout`. To be precise: I need to know, what class (or class file) was initially passed as command line parameter to `java` command.
Dejw
Wow, I'm surprised that the launcher accepts `Derived` as the class name, since it does not contain a `main` method. The `jps` utility must be accessing the `argv[0]` information passed to the native C `main` method.
erickson
I have glanced into implementation - it uses `MonitoredHost`, and `MonitoredVm` classes.
Dejw
Just to be clear: in my example the `Derived` class will be loaded into memory, since I can execute some code inside the `static` block inside the class declaration.
Dejw
Those are implementation dependent.
Thorbjørn Ravn Andersen
@Dejw - yes, I experimented a bit with the Oracle `java` launcher and saw what is happening. `Derived` is loaded, but it isn't on the stack, since the entry point is actually in `Base`. However, if you aren't willing to require any special code in `Derived`, you won't be able to take advantage of the fact that it does get loaded.
erickson
Only advantage I need is the name of the class ;-) Nevertheless, thank You for Your answers - they were very helpful.
Dejw
+4  A: 

Static methods belong to the class they are defined in, and not the instance of the class (same as static/non-static methods). Hence when you are inside getTheClassName you are in a static method defined in the Base class.

For your approach to work, you need to have a non-static method instead. Make it non-static, have a main() in Derived doing a new Derived().getTheClassName()

Thorbjørn Ravn Andersen
I know the workaround You have posted, but I am wondering I can get the name without implementing `main` method in `Derived` class.
Dejw
To my best of knowledge this is not possible in pure Java. You might, however, be able to ask HotSpot about this either through JMX or JVM-specific methods, but that would be a vendor specific solution. Why do you need this?
Thorbjørn Ravn Andersen
I need this for some kind of a app-framework: I will provide an implementation of main method; the user of framework will only derive from `Base` class and will be able to run his/her class with my *boosted* `main`.
Dejw
Tell the users to have a `public static void main(String[] args) { Your.Boosted.Main.main(args); } ` snippet in their Base-derived class. But frankly I think you should ask the user to provide a Derived instance to your boosted main(..)
Thorbjørn Ravn Andersen
Thank You for Your answers ;-)
Dejw
+1  A: 

Try this:

for(final Map.Entry<String, String> entry : System.getenv().entrySet()){
    if(entry.getKey().startsWith("JAVA_MAIN_CLASS"))
        return entry.getValue();
}

But still you should look at others answers. Even if this works, it's a really bad practice.

Colin Hebert