В Java есть ли способ получить параметры командной строки, даже если main() их не сохранила?

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

  •  21-08-2019
  •  | 
  •  

Вопрос

У нас есть программа с main(), которая анализирует определенные CLP, но нигде их не сохраняет.Затем у меня есть свой собственный код подключаемого модуля, которому необходим доступ к оригинальным CLPS (чтобы я мог передавать больше параметров) для него.Однако я не могу изменить main()

Я увидел, что, по-видимому, есть способ сделать это на C#, Я ищу эквивалентное Java-решение в Linux.

Обновить:Очевидно, я в курсе того, как работает main().К сожалению, я не могу изменить существующее приложение или способ его вызова (за исключением CLPs).Я могу получить доступ только через изолированный код плагина.Мой вопрос заключается в том, есть ли способ получить командную строку (а не переменные среды с помощью -D), с помощью которой была вызвана JVM.

Это было полезно?

Решение

Помимо того, что вы каким-то образом выполняете это в main, я думаю, что единственным другим вариантом, который у вас есть, было бы перейти на уровень операционной системы и выполнить некоторые команды для получения аргументов.

В Linux аргументы строки cmd для запущенного процесса хранятся по адресу /процесс/пид/командная строка

Таким образом, чтобы получить их, вам нужно было бы найти идентификатор процесса.Смотрите здесь:

Как программа Java может получить свой собственный идентификатор процесса?

Затем, используя этот открытый /процесс/пид/командная строка и проанализируйте это.Формат этого файла и пример на c приведены здесь:

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

Возможно, было бы лучше обернуть эти два вызова в один сценарий оболочки, который вы вызываете из java.

Пожалуйста, обратите внимание, что это будет крайне непереносимо и немного халтурно.Но если нужно, обязательно...

Другие советы

Решение становится простым, как только вы понимаете, что основной метод Java - это просто еще один статический метод, который принимает массив строк в качестве аргумента.

Создайте новый класс, в котором хранятся CLP, затем вызовите старый класс.Позже вы сможете получить доступ к своим CLP, используя новый класс:

import NotToBeChangedMainClass;

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

}

Наконец, измените любого внешнего вызывающего абонента (напримерлюбые пакетные файлы) использовать MyMainClass вместо NotToBeChangedMainClass.Если вы используете runable jars или что-то подобное, для этого требуется изменить соответствующий файл конфигурации.

Создайте свой собственный основной класс.Сохраните аргументы.Позвоните старому main.

Это могло бы быть проще в использовании System.getProperty и -Dkey=value в командной строке (перед именем основного класса или -jar).

В случае, если у вас нет выбора, вам абсолютно необходимо сохранить все существующие имена классов с их точным названием (как указано в вашем комментарии к моему предыдущему ответу), тогда вы должны использовать AspectJ .

Давайте рассмотрим, что у нас есть этот класс:

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

Во-первых, вам нужно что-то, что содержит аргументы командной строки.Для простоты я буду использовать простой класс со статическим полем:

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

Затем вам нужно определить Аспект, который перехватывает вызовы main и сохраняет аргументы.

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

}

Чтобы попробовать это, я также создал ClassUsingArgumentRegistry:

public class ClassUsingArgumentRegistry {

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

}

Вот и все.Если я включу ткачество AspectJ во время компиляции и запущу результат, используя "java UnmodifyableClassWithMain Foo Bar Baz", я получу следующий результат:

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

Обратите внимание, что это решение очень ограничено, поскольку Linux усекает командную строку, которую оно сохраняет.Поскольку командные строки Java часто имеют очень длинные пути к классам, это очень реальная проблема.

Вот Java-код, реализующий ответ, данный 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));
  }
}

Запуск этого с аргументами "foo bar" в Eclipse дает это для меня:

[/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top