En Java, hay una manera de obtener los parámetros de línea de comandos, incluso si main () no los salvó?

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

  •  21-08-2019
  •  | 
  •  

Pregunta

Tenemos un programa con un main () que analiza determinadas CLP, pero no los salva en cualquier lugar. entonces tengo mi propio código de plug-in que necesita acceso a los originales (CLP para que pueda transmitir más parámetros) para ello. Sin embargo, no puedo cambiar main ()

vi que hay al parecer una manera de hacer esto en C # , estoy buscando una solución equivalente Java en Linux.

ACTUALIZACIÓN: Obviamente, estoy consciente de lo principal () funciona. Por desgracia, no puedo cambiar la aplicación existente o la forma en que se invoca (a excepción de CLP). Yo sólo se puede acceder a través de un código de extensión de espacio aislado. Mi pregunta es si hay una manera de conseguir la línea de comandos (en lugar de las variables de entorno con -D) que la JVM se invocó con.

¿Fue útil?

Solución

Además de hacerlo en el principal, de alguna manera creo que la única opción que tiene sería caer al nivel del sistema operativo y ejecutar algunos comandos para obtener los argumentos.

En Linux los argumentos de la línea cmd para un proceso en ejecución se almacenan en / proc / pid / cmdline

Así que para conseguir que tendría que encontrar el identificador de proceso. Ver aquí:

¿Cómo puede un programa Java obtener su propio ID de proceso?

A continuación, el uso de este abierta / proc / pid / cmdline y analizarlo. El formato de este archivo y un ejemplo en C está aquí:

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

Puede ser que sea mejor para envolver estas dos llamadas en una secuencia de comandos shell que llama desde Java.

Tenga en cuenta que esto va a ser extremadamente portátil y no es un poco hacky. Pero si es necesario debe ...

Otros consejos

La solución es fácil una vez que se da cuenta de que el método principal de Java es sólo otro método estático que toma una matriz de cadenas como argumento.

Crea una nueva clase que almacena los CLP, a continuación, llama a la clase de edad. Más tarde, puede acceder a sus CLP utilizando la nueva clase:

import NotToBeChangedMainClass;

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

}

Por último, el cambio lo interlocutor externo (por ejemplo, los archivos por lotes) para usar en lugar de MyMainClass NotToBeChangedMainClass. Si está utilizando frascos runable o algo similar, es necesario cambiar el archivo de configuración adecuado.

Crea tu propia clase principal. Guardar los argumentos. Llame a la edad main.

Puede ser que sea más fácil de usar y System.getProperty -Dkey=value en la línea de comandos (antes del nombre de la clase principal o -jar).

En caso de que no tiene una opción cualquiera que sea absolutamente necesario retener todos los nombres de las clases existentes con su nombre exacto ( como se indica en su comentario a mi respuesta anterior), entonces usted tiene para ir con AspectJ.

Vamos a considerar que tenemos esta clase:

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

En primer lugar, es necesario algo que mantiene los argumentos de línea de comandos. Voy a utilizar una clase simple con un campo estático por simplicidad:

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

A continuación, es necesario definir un aspecto que intercepta las llamadas a principal y almacena los 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 probarlo, también creó un ClassUsingArgumentRegistry:

public class ClassUsingArgumentRegistry {

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

}

Eso es todo. Si habilito tejer tiempo de compilación de AspectJ y corro el resultado con "java UnmodifyableClassWithMain Foo Bar Baz", consigo la salida siguientes aparatos:

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

Tenga en cuenta que esta solución es muy limitado ya que Linux trunca la línea de comandos que se ahorra. Como las líneas de comandos de Java a menudo tienen muy largas rutas de clases, esto es un problema muy real.

Aquí está el código de Java aplicación de la respuesta 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));
  }
}

Al ejecutar este con argumentos "foo bar" en Eclipse da esto para mí:

[/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top