En Java, il est un moyen d'obtenir les paramètres de ligne de commande, même si principale () ne les a pas sauvés?

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

  •  21-08-2019
  •  | 
  •  

Question

Nous avons un programme avec une main () qui traite certaines CLPs mais ne les enregistre pas partout. alors j'ai mon propre code de plug-in qui doit avoir accès aux originaux (CLPs je peux transmettre plusieurs paramètres) pour elle. Cependant, je ne peux pas changer principal ()

j'ai vu qu'il ya apparemment un façon de le faire en C # , je suis à la recherche d'une solution Java équivalente sous Linux.

MISE À JOUR: De toute évidence, je suis au courant de la façon dont main () fonctionne. Malheureusement, je ne peux pas changer l'application existante ou la façon dont elle est invoquée (sauf pour CLPs). Je ne peux que l'accès via un code de plug-in sandbox. Ma question est de savoir s'il y a un moyen d'obtenir la ligne de commande (plutôt que les variables d'environnement avec -D) que la machine virtuelle Java a été invoquée avec.

Était-ce utile?

La solution

En plus de le faire dans le principal d'une certaine façon, je pense que la seule autre option que vous avez serait de tomber au niveau du système d'exploitation et d'exécuter certaines commandes pour obtenir les arguments.

Sur linux les arguments de ligne cmd pour un processus en cours d'exécution sont stockés à / proc / pid / cmdline

Donc, pour les obtenir, vous devez trouver le numéro de processus. Voir ici:

Comment un programme Java obtenir son propre ID de processus?

Ensuite, en utilisant cette ouverture / proc / pid / cmdline et l'analyser. Le format de ce fichier et un exemple dans c est ici:

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

Il est peut-être préférable d'envelopper ces deux appels dans un script shell que vous appelez de java.

S'il vous plaît noter que ce sera extrêmement non portable et est un peu hacky. Mais s'il le faut ...

Autres conseils

La solution est facile une fois que vous vous rendez compte que la méthode principale de Java est juste une autre méthode statique qui prend un tableau de chaînes comme argument.

Créer une nouvelle classe qui stocke les CLPs, puis appelle l'ancienne classe. Par la suite, vous pouvez accéder à vos CLPs en utilisant la nouvelle classe:

import NotToBeChangedMainClass;

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

}

Enfin, le changement quel que soit l'appelant externe (par exemple tous les fichiers de traitement par lots) à utiliser MyMainClass au lieu de NotToBeChangedMainClass. Si vous utilisez des pots runable ou quelque chose de similaire, cela nécessite de modifier le fichier de configuration appropriée.

Créez votre propre classe principale. Enregistrer les arguments. Appelez l'ancien main.

Il est peut-être plus facile à utiliser et System.getProperty sur la ligne -Dkey=value de commande (avant principal nom de classe ou -jar).

Si vous n'avez pas le choix que vous tout à fait de conserver tous les noms de classe existants avec leur nom exact ( comme indiqué dans votre commentaire à ma réponse précédente), alors vous avez pour aller avec AspectJ.

Considérons que nous avons cette classe:

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

D'abord, vous devez quelque chose qui contient les arguments de ligne de commande. Je vais utiliser une classe simple avec un champ statique pour la simplicité:

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

Ensuite, vous devez vous définissez un aspect qui intercepte les appels à principal et stocke les arguments.

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

}

Pour l'essayer, j'ai aussi créé un ClassUsingArgumentRegistry:

public class ClassUsingArgumentRegistry {

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

}

Voilà. Si je le tissage activer le temps de compilation de AspectJ et exécuter le résultat en utilisant « java UnmodifyableClassWithMain Foo Bar Baz », je reçois la sortie follwing:

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

Notez que cette solution est très limitée que Linux tronque la ligne de commande qu'il sauve. Comme les lignes de commande Java ont souvent très longues classpaths, cela est un problème très réel.

Voici le code Java implémentant la réponse donnée par 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'exécution de ce avec des arguments "foo bar" dans Eclipse donne ceci pour moi:

[/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top