Pergunta

Eu quero determinar o nome da classe onde meu aplicativo foi iniciado, aquele com o método main (), em tempo de execução, mas eu estou em outro segmento e meu stacktrace não percorrer todo o caminho de volta para a classe original.

Eu procurei propriedades do sistema e tudo o que ClassLoader tem para oferecer e chegar a nada. esta informação não é apenas disponíveis?

Graças.

Foi útil?

Solução 5

Eu percebi isso. Alguém pode me dizer se esta variável de ambiente sempre estará por perto em outras implementações de Java em sistemas operacionais? Este no Oracle JVM produz uma string como "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.");
}

Outras dicas

Veja os comentários sobre link fornecido por Tom Hawtin. A solução é nos dias de hoje é (Oracle JVM apenas):

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

testado apenas com o Oracle Java 7. Mais informações sobre casos especiais: http: // bugs.java.com/view_bug.do?bug_id=4827318

Tente usar Tópico .getAllStackTraces () . Ele retorna um mapa dos rastreamentos de pilha de todos os segmentos em execução, não apenas a atual.

O valor ambiente JAVA_MAIN_CLASS não está sempre presente, dependendo da plataforma. Se você quiser apenas para obter um nome da classe "main", que começou o seu processo de Java, você pode fazer isso:

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

Dado o esclarecimento, eu sugiro usar o "Parametrização from Above" idioma. Você tem as informações para começar, manter a preensão dela.

eu colocar em uma RFE 4.827.318 (seis anos atrás!) para algo como isto para uso com corredores de teste.

Como sobre algo como:

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

Isto lhe dará algo como

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)

O segmento principal é provavelmente não guarenteed a ser chamado "main" embora - pode ser melhor para verificar se há um elemento de rastreamento de pilha que contém (main

Editar se o thread principal saiu, isso não é bom!

Eu sugiro colocar essa informação em uma propriedade do sistema. Isso geralmente é simples de fazer quando você iniciar o aplicativo a partir de um script.

Se você não pode fazer isso, sugiro para definir a propriedade no principal método de () de cada aplicação. A maneira mais simples aqui seria ter cada aplicativo derivar de "classe principal" de uma classe base comum e executar um passo de inicialização lá. Costumo fazer isso para o processamento de linha de comando:

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

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

Mesmo se o fio com o método main () tenha terminado e você não estiver usando o Oracle JVM você ainda pode tentar obter as informações do sistema operacional. O código a seguir obtém a linha de comando usado para iniciar o JVM no Linux, mas você pode escrever uma versão para Windows, etc. Você poderia, então, olhar para os argumentos para a JVM para encontrar o ponto de entrada do aplicativo. Pode ser diretamente na linha de comando ou você pode ter o olhar para o Main-Classe: classname no manifesto do jar especificado. Gostaria em primeiro lugar usar System.getProperty ( "sun.java.command") e apenas amigos cair de volta a este mecanismo, se necessário.

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

Aqui está o que eu estou usando, para situações em que você não controla o principal:

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

Outra maneira de obter a classe principal é olhar para essa classe no Thread.getAllStackTraces, para que você possa encontrá-lo ainda frascos dentro, ele funciona em qualquer SDK (Open, a 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;
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top