Führen Sie ein anderes JAR in einem Java-Programm aus

113

Ich hatte mehrere einfache Java-Anwendungen mit den Namen A.jar, B.jar geschrieben.

Jetzt möchte ich ein GUI-Java-Programm schreiben, damit der Benutzer die Taste A drücken kann, um A.jar auszuführen, und die Taste B, um B.jar auszuführen.

Außerdem möchte ich die Laufzeitprozessdetails in meinem GUI-Programm ausgeben.

Irgendein Vorschlag?

Winsontan520
quelle
31
Ich bin mir nicht sicher, warum dies abgelehnt wurde. Erklären Sie ihm, warum seine Annahmen falsch sein könnten, aber stimmen Sie die Frage nicht ab.
William Brendel
-1 Die grundlegende Java-Terminologie wird nicht richtig verwendet und die Frage ist sehr vage und lässt viel für eine zweite Vermutung übrig. Überlegen Sie, ob Sie Ihre Frage mit weiteren Details umformulieren möchten, oder lesen Sie zuerst einfach den Java-Klassenpfad und andere Grundlagen.
Topchef
21
@grigory: Sehen Sie, das hätten Sie zuerst fragen sollen, anstatt sofort abzustimmen. Downvoting ohne nach weiteren Informationen zu fragen, nützt nichts ...
William Brendel
4
@ William, entschuldige, dass du einige Sekunden später als du auf den Knopf gedrückt hast. Ich behalte mir das Recht vor, mit nachfolgendem Kommentar abzustimmen. Es ist frustrierend zu sehen, dass Fragen ohne grundlegende Vorbereitung und / oder Anstrengung gestellt werden, um das Problem zu verstehen oder zu präsentieren. Abstimmungen sind für mich wie ein Tipp in einem Restaurant: Sie geben je nach Servicequalität mehr oder weniger als 12%. Stimmen wir also zu, hier nicht zuzustimmen.
Topchef
1
@topchef Ich bin 11 Jahre zu spät dran, aber du sagst "Es ist frustrierend, wenn Fragen ohne grundlegende Vorbereitung gestellt werden ...". Dann helfen Sie, das Problem zu beheben. Erklären Sie, warum Sie abgelehnt haben. Ansonsten helfen Sie dem Problem überhaupt nicht.
tylerr147

Antworten:

63

Wenn ich das richtig verstehe, möchten Sie die Jars anscheinend in einem separaten Prozess in Ihrer Java-GUI-Anwendung ausführen.

Dazu können Sie Folgendes verwenden:

// Run a java app in a separate system process
Process proc = Runtime.getRuntime().exec("java -jar A.jar");
// Then retreive the process output
InputStream in = proc.getInputStream();
InputStream err = proc.getErrorStream();

Es ist immer eine gute Praxis, die Ausgabe des Prozesses zu puffern.

gjrwebber
quelle
21
Ist diese Lösung portabel?
Pacerier
3
Vielen Dank. Ich habe exec () func mit 3 Parametern ausprobiert, einschließlich des "dir" -Parameters, und es funktioniert nicht. Mit nur einer müssen wir nur die 3 Dateien .jar an der gleichen Stelle ablegen
Duc Tran
Wissen Sie, wie Sie das RuntimeObjekt dieser Java-Anwendung erhalten?
Stommestack
Können wir mit ProcessBuilder eine portablere Version verwenden?
Anand Rockzz
Programm "java" kann nicht ausgeführt werden: CreateProcess error = 2, Das System kann die angegebene Datei nicht finden. Diesen Fehler erhalten.
Gentleman
27

.jar ist nicht ausführbar. Instanziieren Sie Klassen oder rufen Sie eine statische Methode auf.

BEARBEITEN: Fügen Sie beim Erstellen einer JAR einen Eintrag für die Hauptklasse hinzu.

> p.mf (Inhalt von p.mf)

Hauptklasse: pk.Test

>Test.java

package pk;
public class Test{
  public static void main(String []args){
    System.out.println("Hello from Test");
  }
}

Verwenden Sie die Process-Klasse und ihre Methoden.

public class Exec
{
   public static void main(String []args) throws Exception
    {
        Process ps=Runtime.getRuntime().exec(new String[]{"java","-jar","A.jar"});
        ps.waitFor();
        java.io.InputStream is=ps.getInputStream();
        byte b[]=new byte[is.available()];
        is.read(b,0,b.length);
        System.out.println(new String(b));
    }
}
Adatapost
quelle
1
Ich denke, die Idee ist, dass man beim Zugriff auf ein Glas, wie man es dem Klassenpfad hinzufügt, um Klassen daraus zu laden.
Jherico
1
Hinweis: Es funktioniert nur, weil Sie den Java-Bin in Ihrem Pfad haben. Dies ist nicht der Fall für die Standard-Windows-Installation
Poussma
@ AVD: Wo soll die A.jar-Datei aufbewahrt werden?
Logan
1
@logan - In einem Verzeichnis, in das Sie ein Programm laden.
Adatapost
Wird dieser Ansatz einen neuen JVM-Prozess erstellen oder den vorhandenen verwenden?
RahulDeep Attri
17

Hoffe das hilft:

public class JarExecutor {

private BufferedReader error;
private BufferedReader op;
private int exitVal;

public void executeJar(String jarFilePath, List<String> args) throws JarExecutorException {
    // Create run arguments for the

    final List<String> actualArgs = new ArrayList<String>();
    actualArgs.add(0, "java");
    actualArgs.add(1, "-jar");
    actualArgs.add(2, jarFilePath);
    actualArgs.addAll(args);
    try {
        final Runtime re = Runtime.getRuntime();
        //final Process command = re.exec(cmdString, args.toArray(new String[0]));
        final Process command = re.exec(actualArgs.toArray(new String[0]));
        this.error = new BufferedReader(new InputStreamReader(command.getErrorStream()));
        this.op = new BufferedReader(new InputStreamReader(command.getInputStream()));
        // Wait for the application to Finish
        command.waitFor();
        this.exitVal = command.exitValue();
        if (this.exitVal != 0) {
            throw new IOException("Failed to execure jar, " + this.getExecutionLog());
        }

    } catch (final IOException | InterruptedException e) {
        throw new JarExecutorException(e);
    }
}

public String getExecutionLog() {
    String error = "";
    String line;
    try {
        while((line = this.error.readLine()) != null) {
            error = error + "\n" + line;
        }
    } catch (final IOException e) {
    }
    String output = "";
    try {
        while((line = this.op.readLine()) != null) {
            output = output + "\n" + line;
        }
    } catch (final IOException e) {
    }
    try {
        this.error.close();
        this.op.close();
    } catch (final IOException e) {
    }
    return "exitVal: " + this.exitVal + ", error: " + error + ", output: " + output;
}
}
Swarvanu Sengupta
quelle
0

Wenn sich das Glas in Ihrem Klassenpfad befindet und Sie die Hauptklasse kennen, können Sie einfach die Hauptklasse aufrufen. Am Beispiel von DITA-OT:

import org.dita.dost.invoker.CommandLineInvoker;
....
CommandLineInvoker.main('-f', 'html5', '-i', 'samples/sequence.ditamap', '-o', 'test')

Beachten Sie, dass das untergeordnete JAR den Speicherplatz und einen Klassenpfad mit Ihrem JAR teilt, mit allen möglichen Interferenzen, die dazu führen können. Wenn Sie nicht möchten, dass das Zeug verschmutzt wird, haben Sie andere Möglichkeiten, wie oben erwähnt - nämlich:

  • Erstellen Sie einen neuen ClassLoader mit dem Glas darin. Das ist sicherer; Sie können das Wissen des neuen Glases zumindest auf einen Core Classloader beschränken, wenn Sie Dinge mit dem Wissen entwerfen, dass Sie Alien-Gläser verwenden. Das machen wir in meinem Shop für unser Plugins-System. Die Hauptanwendung ist eine winzige Shell mit einer ClassLoader-Factory, einer Kopie der API und dem Wissen, dass die reale Anwendung das erste Plugin ist, für das sie einen ClassLoader erstellen sollte. Plugins sind zwei Jars - Schnittstelle und Implementierung -, die zusammen gezippt werden. Die ClassLoader teilen sich alle Schnittstellen, während jeder ClassLoader nur über Kenntnisse seiner eigenen Implementierung verfügt. Der Stapel ist ein wenig komplex, aber er besteht alle Tests und funktioniert wunderbar.
  • use Runtime.getRuntime.exec(...)(das die JAR vollständig isoliert, aber die normalen Fallstricke "Find the Application", "Escape Your Strings Right", "Platform-Specific WTF" und "OMG System Threads" beim Ausführen von Systembefehlen aufweist.
Fordi
quelle
0

Im Folgenden wird das JAR mit einer Batch-Datei gestartet, falls das Programm als eigenständiges Programm ausgeführt wird:

public static void startExtJarProgram(){
        String extJar = Paths.get("C:\\absolute\\path\\to\\batchfile.bat").toString();
        ProcessBuilder processBuilder = new ProcessBuilder(extJar);
        processBuilder.redirectError(new File(Paths.get("C:\\path\\to\\JavaProcessOutput\\extJar_out_put.txt").toString()));
        processBuilder.redirectInput();
        try {
           final Process process = processBuilder.start();
            try {
                final int exitStatus = process.waitFor();
                if(exitStatus==0){
                    System.out.println("External Jar Started Successfully.");
                    System.exit(0); //or whatever suits 
                }else{
                    System.out.println("There was an error starting external Jar. Perhaps path issues. Use exit code "+exitStatus+" for details.");
                    System.out.println("Check also C:\\path\\to\\JavaProcessOutput\\extJar_out_put.txt file for additional details.");
                    System.exit(1);//whatever
                }
            } catch (InterruptedException ex) {
                System.out.println("InterruptedException: "+ex.getMessage());
            }
        } catch (IOException ex) {
            System.out.println("IOException. Faild to start process. Reason: "+ex.getMessage());
        }
        System.out.println("Process Terminated.");
        System.exit(0);
    }

In der batchfile.bat können wir dann sagen:

@echo off
start /min C:\path\to\jarprogram.jar
Dawood Morris
quelle
-3

Wenn Sie Java 1.6 sind, können Sie auch Folgendes tun:

import javax.tools.JavaCompiler; 
import javax.tools.ToolProvider; 

public class CompilerExample {

    public static void main(String[] args) {
        String fileToCompile = "/Users/rupas/VolatileExample.java";

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        int compilationResult = compiler.run(null, null, null, fileToCompile);

        if (compilationResult == 0) {
            System.out.println("Compilation is successful");
        } else {
            System.out.println("Compilation Failed");
        }
    }
}
Rupa
quelle
4
Ich glaube nicht, dass dies die Frage des OP beantwortet
Sri Harsha Chilakapati