5

特定のCLPを解析するが、どこにも保存しないmain()を備えたプログラムがあります。次に、元のCLPにアクセスする必要がある独自のプラグインコードがあります(これにより、より多くのパラメーターを送信できます)。ただし、main()を変更することはできません

どうやらC#でこれを行う方法があることがわかりました。Linuxで同等のJavaソリューションを探しています。

更新:明らかに、私はmain()がどのように機能するかを知っています。残念ながら、既存のアプリケーションまたはその呼び出し方法を変更することはできません(CLPを除く)。サンドボックス化されたプラグインコードを介してのみアクセスできます。私の質問は、JVMが呼び出されたコマンドライン(-Dを使用した環境変数ではなく)を取得する方法があるかどうかです。

4

5 に答える 5

4

Javaのmainメソッドが、引数としてString配列を受け取る別の静的メソッドであることがわかったら、解決策は簡単です。

CLPを格納する新しいクラスを作成してから、古いクラスを呼び出します。後で、新しいクラスを使用してCLPにアクセスできます。

import NotToBeChangedMainClass;

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

}

最後に、NotToBeChangedMainClassの代わりにMyMainClassを使用するように、外部の呼び出し元(バッチファイルなど)を変更します。実行可能なjarなどを使用している場合は、適切な構成ファイルを変更する必要があります。

于 2009-06-29T14:30:55.153 に答える
4

何らかの方法でメインでそれを行うこととは別に、あなたが持っている唯一の他のオプションは、オペレーティングシステムレベルにドロップし、引数を取得するためにいくつかのコマンドを実行することだと思います。

Linuxでは、実行中のプロセスのcmd行引数は/ proc / pid /cmdlineに保存されます。

したがって、それらを取得するには、プロセスIDを見つける必要があります。ここを参照してください:

Javaプログラムはどのようにして独自のプロセスIDを取得できますか?

次に、このopen / proc / pid /cmdlineを使用して解析します。このファイルの形式とcの例は次のとおりです。

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

これらの2つの呼び出しを、Javaから呼び出す1つのシェルスクリプトにラップするのが最適な場合があります。

これは非常に移植性が低く、少しハッキーであることに注意してください。しかし、必要に応じて...

于 2009-06-29T19:50:12.353 に答える
1

独自のメインクラスを作成します。引数を保存します。古いと呼びmainます。

コマンドライン(メインクラス名またはの前)で使用する方が簡単な場合がありSystem.getPropertyます。-Dkey=value-jar

于 2009-06-29T14:19:41.057 に答える
1

選択肢がない場合は、既存のクラス名をすべて正確な名前で保持する必要があります(私の前の回答へのコメントで述べたように)、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]
于 2009-06-30T10:15:05.903 に答える
0

Linuxは保存したコマンドラインを切り捨てるため、このソリューションは非常に制限されていることに注意してください。Javaコマンドラインには非常に長いクラスパスがあることが多いため、これは非常に現実的な問題です。

これがPablojimによって与えられた答えを実装するJavaコードです。

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

Eclipseで引数「foobar」を使用してこれを実行すると、次のようになります。

[/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]
于 2016-09-08T19:54:43.847 に答える