How to determine main class at runtime in threaded

2019-02-08 07:51发布

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.

10条回答
乱世女痞
2楼-- · 2019-02-08 08:20

Here's what I'm using, for situations where you don't control the main:

public static Class<?> getMainClass() {
  // find the class that called us, and use their "target/classes"
  final Map<Thread, StackTraceElement[]> traces = Thread.getAllStackTraces();
  for (Entry<Thread, StackTraceElement[]> trace : traces.entrySet()) {
    if ("main".equals(trace.getKey().getName())) {
      // Using a thread named main is best...
      final StackTraceElement[] els = trace.getValue();
      int i = els.length - 1;
      StackTraceElement best = els[--i];
      String cls = best.getClassName();
      while (i > 0 && isSystemClass(cls)) {
        // if the main class is likely an ide,
        // then we should look higher...
        while (i-- > 0) {
          if ("main".equals(els[i].getMethodName())) {
            best = els[i];
            cls = best.getClassName();
            break;
          }
        }
      }
      if (isSystemClass(cls)) {
        i = els.length - 1;
        best = els[i];
        while (isSystemClass(cls) && i --> 0) {
          best = els[i];
          cls = best.getClassName();
        }
      }
      try {
        Class mainClass = Class.forName(best.getClassName());
        return mainClass;
      } catch (ClassNotFoundException e) {
        throw X_Util.rethrow(e);
      }
    }
  }
  return null;
}

private static boolean isSystemClass(String cls) {
  return cls.startsWith("java.") ||
      cls.startsWith("sun.") ||
      cls.startsWith("org.apache.maven.") ||
      cls.contains(".intellij.") ||
      cls.startsWith("org.junit") ||
      cls.startsWith("junit.") ||
      cls.contains(".eclipse") ||
      cls.contains("netbeans");
}
查看更多
乱世女痞
3楼-- · 2019-02-08 08:25

Even if the thread with the main() method has terminated and you are not using the Oracle JVM you can still attempt to get the information from the operating system. The code below obtains the command line used to start the JVM under Linux but you could write a version for Windows, etc. You could then look at the arguments to the JVM to find the application entry point. It might be directly on the command line or you might have look for Main-Class: classname in the manifest of the specified jar. I would first use System.getProperty("sun.java.command") and friends only falling back to this mechanism if necessary.

public final static long getSelfPid() {
    // Java 9 only
    // return ProcessHandle.current().getPid();
    try {
        return Long.parseLong(new File("/proc/self").getCanonicalFile().getName());
    } catch( Exception e ) {
        return -1;
    }
}

public final static String getJVMCommandLine() {
    try {
        // Java 9 only
        // long pid = ProcessHandle.current().getPid();
        long pid = getSelfPid();
        byte[] encoded = Files.readAllBytes(Paths.get("/proc/"+pid+"/cmdline"));
        // assume ISO_8859_1, but could look in /proc/<pid>/environ for LANG or something I suppose
        String commandLine = new String( encoded, StandardCharsets.ISO_8859_1 ); 
        String modifiedCommandLine = commandLine.replace((char)0, ' ').trim();
        return modifiedCommandLine;
    } catch( Exception e ) {
        return null;
    }
}`
查看更多
Animai°情兽
4楼-- · 2019-02-08 08:26

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

查看更多
Fickle 薄情
5楼-- · 2019-02-08 08:29

Given the clarification, I suggest using the "Parameterisation from Above" idiom. 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.

查看更多
登录 后发表回答