In Java, c'è un modo per ottenere i parametri della riga di comando, anche se main () non li salva?

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

  •  21-08-2019
  •  | 
  •  

Domanda

Abbiamo un programma con un main () che analizza alcuni CLP, ma non salva da nessuna parte. Ho poi ho il mio codice di plug-in che ha bisogno di accedere alle CLP originali (in modo da poter trasmettere più parametri) per esso. Tuttavia, non posso cambiare main ()

ho visto che non v'è apparentemente un modo per fare questo in C # , sto cercando una soluzione Java equivalente su Linux.

UPDATE: Ovviamente, io sono a conoscenza di come main () funziona. Purtroppo, non riesco a modificare l'applicazione esistente o il modo in cui viene richiamato (tranne che per CLP). Posso accedere solo tramite un codice del plugin sandbox. La mia domanda è se c'è un modo per ottenere la linea di comando (piuttosto che le variabili di ambiente con -D) che la JVM è stato richiamato con.

È stato utile?

Soluzione

Oltre a farlo in principale in qualche modo penso che l'unica altra opzione che avete sarebbe quello di cadere al livello di sistema operativo ed eseguire alcuni comandi per ottenere gli argomenti.

In Linux gli argomenti della riga di cmd per un processo in esecuzione vengono memorizzati in / proc / pid / cmdline

Quindi, per farli si dovrebbe trovare l'ID del processo. Vedi qui:

Come può un programma Java ottenere il proprio ID di processo?

Quindi, utilizzando questo open / proc / pid / cmdline e analizzarlo. Il formato di questo file e un esempio in C è qui:

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

Potrebbe essere meglio per avvolgere questi due chiamate in script di una conchiglia che chiamate da Java.

Si prega di notare che questo sarà estremamente portatile e non è un po 'hacky. Ma se i bisogni deve ...

Altri suggerimenti

La soluzione è facile una volta che ci si rende conto che il metodo principale di Java è solo un altro metodo statico che prende un array di stringhe come argomento.

Creare una nuova classe che memorizza i CLP, quindi chiama la vecchia classe. In seguito, è possibile accedere ai CLP utilizzando la nuova classe:

import NotToBeChangedMainClass;

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

}

Infine, il cambiamento qualsiasi chiamante esterno (ad esempio tutti i file batch) da utilizzare al posto di MyMainClass NotToBeChangedMainClass. Se si utilizza vasetti runable o qualcosa di simile, questo richiede la modifica del file di configurazione appropriata.

Crea la tua classe principale. Salvare gli argomenti. Chiamare il vecchio main.

Potrebbe essere più facile da usare e System.getProperty -Dkey=value sulla riga di comando (prima il nome della classe principale o -jar).

Nel caso in cui non si dispone di una scelta qualsiasi dovete assolutamente conservare tutti i nomi di classe esistenti con il loro nome esatto ( come indicato nel tuo commento alla mia risposta precedente), allora si hanno per andare con AspectJ.

Consideriamo che abbiamo questa classe:

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

In primo luogo, è necessario qualcosa che contiene gli argomenti della riga di comando. Userò una semplice classe con un campo statico per semplicità:

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

Quindi, è necessario definire un aspetto che intercetta le chiamate a principale e memorizza gli argomenti.

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

}

Per provarlo, ho anche creato un ClassUsingArgumentRegistry:

public class ClassUsingArgumentRegistry {

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

}

Questo è tutto. Se permetto momento della compilazione di tessitura di AspectJ e corro il risultato usando "java UnmodifyableClassWithMain Foo Bar Baz", ottengo l'uscita follwing:

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

Si noti che questa soluzione è molto limitato come Linux tronca la riga di comando che consente di risparmiare. Come linee di comando di Java hanno spesso molto lunghi percorsi di classe, questo è un problema molto reale.

Ecco il codice Java che implementa la risposta data da 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));
  }
}

L'esecuzione di questo con gli argomenti "foo bar" in Eclipse dà questo per me:

[/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top