Esegui un altro jar in un programma Java


115

Avevo scritto diverse semplici applicazioni java denominate A.jar, B.jar.

Ora voglio scrivere un programma java GUI in modo che l'utente possa premere il pulsante A per eseguire A.jar e il pulsante B per eseguire B.jar.

Inoltre voglio visualizzare i dettagli del processo di runtime nel mio programma GUI.

Qualche suggerimento?


31
Non sono sicuro del motivo per cui è stato respinto. Spiegagli perché le sue supposizioni potrebbero essere sbagliate, ma non sottovalutare la domanda.
William Brendel

-1 la terminologia Java di base non viene utilizzata correttamente e la domanda è molto vaga e lascia molto per una seconda ipotesi. Considera l'idea di riformulare la tua domanda con maggiori dettagli o leggi prima il classpath Java e altre nozioni di base.
topchef

21
@grigory: vedi, questo è quello che avresti dovuto chiedere in primo luogo, invece di votare subito. Downvoting senza nemmeno chiedere maggiori informazioni non serve a niente ...
William Brendel

4
@ William, scusa per aver premuto il pulsante pochi secondi dopo. Mi riservo il diritto di votare a favore con successivo commento. È frustrante vedere le domande poste senza una preparazione di base e / o uno sforzo per comprendere o presentare il problema. Il voto per me è come un suggerimento in un ristorante: dai più o meno del 12% standard a seconda della qualità del servizio. Quindi accettiamo di non essere d'accordo qui.
topchef

1
@topchef Sono in ritardo di 11 anni, ma tu dici "È frustrante vedere le domande poste senza una preparazione di base ...". Quindi aiutaci a risolverlo. Spiega perché hai svalutato. Altrimenti non stai aiutando affatto il problema.
tylerr147

Risposte:


63

Se ho capito bene, sembra che tu voglia eseguire i jar in un processo separato dall'interno della tua applicazione java GUI.

Per fare questo puoi usare:

// 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();

È sempre buona norma tamponare l'output del processo.


21
Questa soluzione è portatile?
Pacerier

3
Grazie. Ho provato exec () func con 3 parametri, incluso il parametro "dir" e non funziona. Con uno solo, dobbiamo solo mettere i 3 file .jar nello stesso posto
Duc Tran

Sai come ottenere l' Runtimeoggetto di quell'applicazione Java?
stommestack

Possiamo usare una versione più portabile, usando ProcessBuilder?
Anand Rockzz

Impossibile eseguire il programma "java": errore CreateProcess = 2, il sistema non riesce a trovare il file specificato. Ottenere questo errore.
Gentleman

27

.jar non è eseguibile. Istanziare classi o effettuare chiamate a qualsiasi metodo statico.

MODIFICA: aggiungi la voce della classe principale durante la creazione di un JAR.

> p.mf (contenuto di p.mf)

Classe principale: pk.Test

>Test.java

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

Usa la classe Process ei suoi metodi,

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

1
Penso che l'idea sia che, dato l'accesso a un jar, come aggiungerlo al classpath per caricarne le classi.
Jherico

1
Nota: funziona solo perché hai il java bin nel tuo PERCORSO, questo non è il caso dell'installazione predefinita di Windows
poussma

@AVD: dove dovrebbe essere conservato il file A.jar?
logan

1
@logan - In una directory in cui stai caricando un programma.
adatapost

Questo approccio creerà un nuovo processo JVM o utilizzerà quello esistente?
Rahul Deep Attri

17

Spero che questo ti aiuti:

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

0

Se il jar è nel tuo classpath e conosci la sua classe principale, puoi semplicemente invocare la classe principale. Usando DITA-OT come esempio:

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

Nota che questo farà in modo che il jar subordinato condivida lo spazio di memoria e un classpath con il tuo jar, con tutto il potenziale di interferenza che può causare. Se non vuoi che quella roba venga inquinata, hai altre opzioni, come menzionato sopra, vale a dire:

  • crea un nuovo ClassLoader con il jar al suo interno. Questo è più sicuro; puoi almeno isolare la conoscenza del nuovo jar su un classloader di base se progetti le cose con la consapevolezza che farai uso di vasi alieni. È quello che facciamo nel mio negozio per il nostro sistema di plugin; l'applicazione principale è una minuscola shell con una factory ClassLoader, una copia dell'API e la consapevolezza che la vera applicazione è il primo plugin per cui dovrebbe costruire un ClassLoader. I plugin sono una coppia di barattoli - interfaccia e implementazione - che vengono compressi insieme. Tutti i ClassLoader condividono tutte le interfacce, mentre ogni ClassLoader conosce solo la propria implementazione. Lo stack è un po 'complesso, ma supera tutti i test e funziona a meraviglia.
  • use Runtime.getRuntime.exec(...)(che isola completamente il jar, ma ha le normali insidie ​​"trova l'applicazione", "esci dalle stringhe corrette", "WTF specifico della piattaforma" e "Thread di sistema OMG" dei comandi di sistema in esecuzione.

0

Quanto segue funziona avviando il jar con un file batch, nel caso in cui il programma venga eseguito come stand alone:

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

Nel batchfile.bat allora possiamo dire:

@echo off
start /min C:\path\to\jarprogram.jar

-3

Se sei java 1.6, puoi anche fare quanto segue:

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

4
Non credo che questo risponda alla domanda dell'OP
Sri Harsha Chilakapati
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.