Frage

Ich will die Klassennamen bestimmen, wo meine Anwendung gestartet, das mit der main () Methode, zur Laufzeit, aber ich bin in einem anderen Thread und meine Stacktrace nicht den ganzen Weg auf die ursprüngliche Klasse geht zurück.

Ich habe Eigenschaften-System gesucht und alles, was Classloader zu bieten hat, und kommt mit nichts. Ist diese Information einfach nicht verfügbar?

Danke.

War es hilfreich?

Lösung 5

ich es herausgefunden. Kann mir jemand sagen, ob diese Umgebungsvariablen in anderen Java-Implementierungen für alle Betriebssysteme immer rund sein? Diese auf Oracle JVM liefert einen String wie "org.x.y.ClassName"

public static String getMainClassName() {
  for (final Map.Entry<String, String> entry : System.getenv().entrySet())
    if (entry.getKey().startsWith("JAVA_MAIN_CLASS")) // like JAVA_MAIN_CLASS_13328
      return entry.getValue();
  throw new IllegalStateException("Cannot determine main class.");
}

Andere Tipps

Siehe die Kommentare auf Link von Tom Hawtin gegeben. Eine Lösung ist in diesen Tagen (Oracle JVM nur):

public static String getMainClassAndArgs() {
    return System.getProperty("sun.java.command"); // like "org.x.y.Main arg1 arg2"
}

Getestet nur mit Oracle Java 7. Weitere Informationen über Sonderfälle: http: // bugs.java.com/view_bug.do?bug_id=4827318

Versuchen Sie Faden .getAllStackTraces () . Es gibt eine Karte des Stack-Traces aus allen laufenden Threads, nicht nur die aktuellen.

Der Wert JAVA_MAIN_CLASS Umgebung ist nicht immer vorhanden abhängig von der Plattform. Wenn Sie nur einen Namen der „main“ Klasse erhalten möchten, dass Ihre Java-Prozess gestartet, Sie können dies tun:

  public static String getMainClassName()
  {
    StackTraceElement trace[] = Thread.currentThread().getStackTrace();
    if (trace.length > 0) {
      return trace[trace.length - 1].getClassName();
    }
    return "Unknown";
  } 

die Klärung Da ich die „Parametrisierung von oben“ Idiom schlage vor, mit. Sie haben die Informationen zu beginnen, halten Sie halten es.

Ich habe in einem RFE setzen 4.827.318 (vor sechs Jahren!) für so etwas wie dies für die Verwendung mit Test Läufer.

Wie wäre es so etwas wie:

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);
        }
    }
}

Dies gibt Ihnen so etwas wie

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)

Der Haupt-Thread ist guarenteed wahrscheinlich nicht "main" obwohl genannt zu werden - könnte besser sein für einen Stapel Spurenelement zu überprüfen, die (main enthält

Bearbeiten , wenn der Haupt-Thread beendet wird, ist dies nicht gut!

Ich schlage vor, diese Informationen in eine Systemeigenschaft zu setzen. Dies ist in der Regel einfach zu tun, wenn Sie Ihre Anwendung von einem Skript starten.

Wenn Sie das nicht tun können, schlage ich vor, die Eigenschaft in der Methode main () jede Anwendung einzustellen. Der einfachste Weg wäre hier jede App zu haben ableiten, es ist „Hauptklasse“ von einer gemeinsamen Basisklasse und führt dort einen Init-Schritt. Ich tue dies oft für die Kommandozeilen-Verarbeitung:

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

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

Auch wenn der Faden mit der Methode main () beendet ist und Sie die Oracle JVM nicht verwenden, können Sie immer noch die Informationen aus dem Betriebssystem zu bekommen versuchen. Der folgende Code erhält die Befehlszeile verwendet, um die JVM unter Linux zu starten, aber man könnte eine Version für Windows usw. schreiben Sie dann auf die Argumente an die JVM aussehen könnte die Anwendung Einstiegspunkt zu finden. Es könnte direkt auf der Kommandozeile oder Sie könnten Blick für Main-Klasse haben: im Manifest der angegebenen jar Klassennamen. Ich würde zuerst System.getProperty ( „sun.java.command“) verwenden und Freunde nur auf diesen Mechanismus zurückzufallen, wenn nötig.

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;
    }
}`

Hier ist, was ich verwende, für Situationen, in denen Sie kontrollieren nicht die Haupt:

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");
}

Eine weitere Möglichkeit, Hauptklasse zu bekommen, ist auf Thread.getAllStackTraces für diese Klasse aussehen, so könnte man es sogar in Gläser finden, es funktioniert auf jedem SDK (Open, Oracle ...):

private static Class<?> mainClass = null;

public static Class<?> getMainClass()
{
    if (mainClass == null)
    {
        Map<Thread, StackTraceElement[]> threadSet = Thread.getAllStackTraces();
        for (Map.Entry<Thread, StackTraceElement[]> entry : threadSet.entrySet())
        {
            for (StackTraceElement stack : entry.getValue())
            {
                try
                {
                    String stackClass = stack.getClassName();
                    if (stackClass != null && stackClass.indexOf("$") > 0)
                    {
                        stackClass = stackClass.substring(0, stackClass.lastIndexOf("$"));
                    }
                    Class<?> instance = Class.forName(stackClass);
                    Method method = instance.getDeclaredMethod("main", new Class[]
                    {
                        String[].class
                    });
                    if (Modifier.isStatic(method.getModifiers()))
                    {
                        mainClass = instance;
                        break;
                    }
                }
                catch (Exception ex)
                {
                }
            }
        }
        return mainClass;
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top