2009-06-29 14 views
4

Wir haben ein Programm mit einem main(), das bestimmte CLPs analysiert, sie aber nicht irgendwo speichert. Ich habe dann meinen eigenen Plug-in-Code, der Zugriff auf die ursprünglichen CLPs benötigt (damit ich weitere Parameter übertragen kann). Ich kann jedoch nicht ändern Haupt()Gibt es in Java eine Möglichkeit, die Befehlszeilenparameter auch dann zu erhalten, wenn main() sie nicht gespeichert hat?

I saw that there is apparently a way to do this in C#, ich bin auf der Suche nach einer gleichwertigen Java-Lösung unter Linux.

UPDATE: Offensichtlich weiß ich, wie main() funktioniert. Leider kann ich die vorhandene Anwendung oder die Art, wie sie aufgerufen wird, nicht ändern (außer für CLPs). Ich kann nur über einen Sandbox-Plugin-Code zugreifen. Meine Frage ist, ob es eine Möglichkeit gibt, die Befehlszeile (anstatt die Umgebungsvariablen mit -D) zu erhalten, mit der die JVM aufgerufen wurde.

+1

Ich sehe nichts in java.lang.Runtime oder-System. –

+0

Ich denke, dass .NET OS-spezifische Methoden verwendet, um die CLPs des aktuellen Prozesses abzurufen. – kgiannakakis

Antwort

4

Abgesehen davon, dass ich es irgendwie in main mache, denke ich, die einzige andere Option, die Sie haben, wäre, auf die Betriebssystemebene zu wechseln und einige Befehle auszuführen, um die Argumente zu bekommen.

auf das cmd Zeilenargument für einen laufenden Prozess Linux auf /proc/pid /cmdline

So gespeichert, sie erhalten Sie die Prozess-ID finden müßten. Siehe hier:

How can a Java program get its own process ID?

Dann mit dieser offenen /proc/pid /cmdline und analysiert es. Das Format dieser Datei und ein Beispiel in c ist hier:

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

Es wäre am besten, diese beiden Anrufe in ein Shell-Skript zu wickeln, die Sie von Java aufrufen.

Bitte beachten Sie, dass dies nicht tragbar sein wird und ein bisschen hacky ist. Aber wenn Bedürfnisse müssen ...

+1

Beachten Sie, dass diese Lösung ist begrenzt, da Linux die Befehlszeile, die es speichert, abschneidet (es ist konfigurierbar, glaube ich, aber ein paar K standardmäßig.) Da Java-Befehlszeilen oft sehr lang sind, weil sie Klassenpfade enthalten, wird dieses Limit leicht erreicht. – mab

1

Erstellen Sie Ihre eigene Hauptklasse. Speichere die Argumente. Rufen Sie die alte main.

Es könnte einfacher sein, System.getProperty und -Dkey=value in der Befehlszeile (vor Hauptklassenname oder -jar) zu verwenden.

+0

Leider kann ich nicht ändern main() ... Doing dies mit der -D ist auch ein Problem, da ich nur die Kontrolle über die Standard-CLPs ... :( – Uri

+5

Dies erfordert keine Änderung main, nur die Befehlszeile. –

4

Die Lösung ist einfach, wenn Sie feststellen, dass Javas Hauptmethode nur eine andere statische Methode ist, die ein String-Array als Argument verwendet.

Erstellen Sie eine neue Klasse, in der die CLPs gespeichert sind, und rufen Sie dann die alte Klasse auf. Später können Sie Ihre CLPs mit der neuen Klasse zugreifen:

import NotToBeChangedMainClass; 

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

}

Schließlich Änderung unabhängig von externen Anrufer (z alle Batch-Dateien) verwenden MyMainClass statt NotToBeChangedMainClass. Wenn Sie runable jars oder ähnliches verwenden, müssen Sie die entsprechende Konfigurationsdatei ändern.

+0

Offensichtlich ist mir bekannt, wie main() funktioniert. Leider kann ich die vorhandene Anwendung oder die Art, wie sie aufgerufen wird, nicht ändern (außer CLPs). Ich kann nur über einen Sandkasten-Plugin-Code zugreifen. – Uri

1

Falls Sie keine Auswahl haben müssen Sie unbedingt alle vorhandenen Klassennamen mit ihrem genauen Namen (as stated in your comment zu meiner vorherigen Antwort), dann müssen Sie mit AspectJ gehen .

Wir betrachten wir diese Klasse haben:

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

Zuerst müssen Sie etwas, das die Befehlszeilenargumente enthält. Ich werde eine einfache Klasse mit einem statischen Feld der Einfachheit halber verwenden: Dann

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

, müssen Sie Sie einen Aspect definieren, die Anrufe zur Haupt abfängt und speichert die Argumente.

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

} 

Denn es aus, ich versucht, schuf auch eine ClassUsingArgumentRegistry:

public class ClassUsingArgumentRegistry { 

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

} 

Das ist es. Wenn ich AspectJ die Kompilierung Weben ermöglichen und das Ergebnis mit „java UnmodifyableClassWithMain Foo Bar Baz“ laufen, bekomme ich die follwing Ausgabe:

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

Beachten Sie, dass diese Lösung sehr wie Linux beschränkt kürzt die Befehlszeile, die es spart. Da Java-Befehlszeilen oft sehr lange Klassenpfade haben, ist dies ein sehr reales Problem.

Hier ist Java Code, der die Antwort von Pablojim implementiert.

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

das Lauf mit Argumenten "foo bar" in Eclipse gibt es für mich:

[/usr/lib/jvm/java-8-oracle/bin/java, -Dfile.encoding=UTF-8, -classpath, /home/mab/workspace/test/bin, test.Test, foo, bar]