Em Java, há uma maneira de obter os parâmetros de linha de comando, mesmo que main () não salvá-los?

StackOverflow https://stackoverflow.com/questions/1058531

  •  21-08-2019
  •  | 
  •  

Pergunta

Temos um programa com um main () que analisa certos CLPs, mas não salva-los em qualquer lugar. Em seguida, tenho meu próprio plug-in de código que precisa de acesso aos CLPs originais (para que eu possa transmitir mais parâmetros) para ele. No entanto, eu não posso mudar main ()

vi que não há aparentemente um maneira de fazer isso em C # , eu estou procurando uma solução Java equivalente em Linux.

UPDATE: Obviamente, eu estou ciente de como main () funciona. Infelizmente, eu não posso mudar a aplicação existente ou a forma como ela é invocada (exceto para CLPs). Eu só pode acessar através de um código do plugin no modo seguro. A minha pergunta é se existe uma maneira de obter a linha de comando (em vez seguida, as variáveis ??de ambiente com -D) que a JVM foi chamado com.

Foi útil?

Solução

Além de fazê-lo no principal, de alguma forma eu acho que a única outra opção que você tem seria a cair para o nível do sistema operacional e executar alguns comandos para obter os argumentos.

No linux os argumentos de linha de cmd para um processo em execução são armazenados em / proc / pid / cmdline

Assim, para obtê-los, você teria que encontrar o ID do processo. Veja aqui:

Como pode um programa Java obter o seu próprio ID processo?

Em seguida, usando esta aberta / proc / pid / cmdline e analisá-lo. O formato deste arquivo e um exemplo em c está aqui:

http : //www.unix.com/unix-advanced-expert-users/86740-retrieving-command-line-arguments-particular-pid.html

Seria melhor para embrulhar estas duas chamadas em um shell script que você chama de Java.

Por favor note que este será extremamente não portátil e é um pouco hacky. Mas se as necessidades deve ...

Outras dicas

A solução é fácil uma vez que você perceber que o principal método de Java é apenas mais um método estático que leva uma matriz String como argumento.

Criar uma nova classe que armazena os CLPs, em seguida, chama a velha classe. Mais tarde, você pode acessar seus CLPs usando a nova classe:

import NotToBeChangedMainClass;

public MyMainClass {
  public static final String[] ARGUMENTS;
  public static void main(String ... args) {
    ARGUMENTS = args;
    NotToBeChangedMainClass.main(args);
  }

}

Finalmente, a mudança que quer chamador externo (por exemplo, todos os arquivos em lote) para usar MyMainClass vez de NotToBeChangedMainClass. Se você estiver usando frascos runable ou algo semelhante, isso requer mudar o arquivo de configuração apropriada.

Crie a sua própria classe principal. Salvar os argumentos. Chame o velho main.

Pode ser mais fácil de usar System.getProperty e -Dkey=value na linha de comando (antes do nome da classe principal ou -jar).

No caso de você não tem uma escolha qualquer que seja absolutamente necessário manter todos os nomes de classe existentes com o seu nome exacto ( como afirmou em seu comentário para a minha resposta anterior), então você tem para ir com AspectJ.

Vamos considerar temos essa classe:

public class UnmodifyableClassWithMain {
  public static void main(String[] args) {
    System.out.println("In main");
    new ClassUsingArgumentRegistry();
  }
}

Em primeiro lugar, você precisa de algo que mantém os argumentos de linha de comando. Vou usar uma classe simples com um campo estático para a simplicidade:

public class ArgumentRegistry {
  public static String[] ARGS;
}

Em seguida, você precisa definir um aspecto que intercepta chamadas para principal e armazena os argumentos.

public aspect StoreArgumentsOfMain {

  /**
   * This pointcut intercepts all calls to methods called main with a string array as
   * argument.
   */
  pointcut mainMethod(String[] arguments): execution(void main(String[])) && args(arguments);

  /**
   * Before the original main method gets called, store the arguments in the registry.
   */
  before(String[] arguments): mainMethod(arguments) {
    System.out.println("Storing arguments");
    ArgumentRegistry.ARGS = arguments;
  }

}

Para testá-lo, eu também criou uma ClassUsingArgumentRegistry:

public class ClassUsingArgumentRegistry {

  public ClassUsingArgumentRegistry() {
    System.out.println("Arguments: " + java.util.Arrays.toString(ArgumentRegistry.ARGS));
  }

}

É isso. Se eu permitir tecelagem tempo de compilação do AspectJ e correr o resultado usando "java UnmodifyableClassWithMain Foo Bar Baz", recebo a saída follwing:

Storing arguments
In main
Arguments: [foo, bar, baz]

Note que esta solução é muito limitado como Linux trunca a linha de comando que ele salva. Como linhas de comando Java, muitas vezes têm classpaths muito longos, este é um problema muito real.

Aqui está o código Java implementação da resposta dada por Pablojim.

package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test {
  public static List<String> getLinuxCmdline(int maxBytesToRead) throws IOException {
    List<String> result = new ArrayList<>();
    String pid = new File("/proc/self").getCanonicalFile().getName();
    File cmdlineFile = new File("/proc/" + pid + "/cmdline");
    final int growBy = 1024;
    try (FileInputStream is = new FileInputStream(cmdlineFile);) {
      byte[] data = new byte[Math.min(growBy, maxBytesToRead)];
      int totalRead = 0; 
      while (totalRead < maxBytesToRead) {
        int read = is.read(data, totalRead, data.length - totalRead);
        if (read > 0) {
          totalRead += read;
          if (data.length == totalRead) {
            data = Arrays.copyOf(data, Math.min(data.length + growBy, maxBytesToRead));
          }
        } else {
          break;
        }
      }
      int start = 0;
      int scan = 0;
      while (scan < totalRead) {
        if (data[scan] == 0) {
          result.add(new String(Arrays.copyOfRange(data, start, scan)));
          start = scan + 1;
        }
        scan++;
      }
      if (scan - start > 0) result.add(new String(Arrays.copyOfRange(data, start, scan)));        }
    return result;
  }

  public static void main(String[] args) throws IOException {
    System.out.println(getLinuxCmdline(Integer.MAX_VALUE));
  }
}

A execução deste com argumentos "foo bar" em Eclipse dá isso para mim:

[/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top