Exécuter un autre jar dans un programme Java

115

J'avais écrit plusieurs applications java simples nommées A.jar, B.jar.

Maintenant, je veux écrire un programme java GUI afin que l'utilisateur puisse appuyer sur le bouton A pour exécuter A.jar et le bouton B pour exécuter B.jar.

Je souhaite également afficher les détails du processus d'exécution dans mon programme GUI.

Toute suggestion?

winsontan520
la source
31
Je ne sais pas pourquoi cela a été rejeté. Expliquez-lui pourquoi ses hypothèses pourraient être fausses, mais ne rejetez pas la question.
William Brendel
-1 La terminologie Java de base n'est pas utilisée correctement et la question est très vague et laisse beaucoup à deviner. Envisagez de reformuler votre question avec plus de détails ou lisez d'abord le chemin de classe Java et d'autres bases.
topchef
21
@grigory: Voyez, c'est ce que vous auriez dû demander en premier lieu, au lieu de voter immédiatement. Voter à la baisse sans même demander plus d'informations ne sert à rien ...
William Brendel
4
@William, désolé d'avoir appuyé sur le bouton quelques secondes plus tard que vous. Je me réserve le droit de voter contre avec des commentaires ultérieurs. Il est frustrant de voir des questions posées sans préparation de base et / ou effort pour comprendre ou présenter le problème. Voter, c'est comme un pourboire dans un restaurant pour moi: vous donnez plus ou moins que la norme de 12% selon la qualité du service. Alors acceptons de ne pas être d'accord ici.
topchef
1
@topchef J'ai 11 ans de retard, mais vous dites: "C'est frustrant de voir des questions posées sans préparation de base ...". Alors aidez à le réparer. Expliquez pourquoi vous avez voté contre. Sinon, vous n'aidez pas du tout le problème.
tylerr147

Réponses:

63

Si je comprends bien, il semble que vous souhaitiez exécuter les fichiers JAR dans un processus distinct depuis votre application java GUI.

Pour ce faire, vous pouvez utiliser:

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

Il est toujours bon de tamponner la sortie du processus.

gjrwebber
la source
21
Cette solution est-elle portable?
Pacerier
3
Merci. J'ai essayé exec () func avec 3 paramètres, y compris le paramètre "dir" et cela ne fonctionne pas. Avec un seul, il suffit de mettre les 3 fichiers .jar au même endroit
Duc Tran
Savez-vous comment obtenir l' Runtimeobjet de cette application java?
stommestack
Pouvons-nous utiliser une version plus portable, utilisant ProcessBuilder?
Anand Rockzz
Impossible d'exécuter le programme "java": erreur CreateProcess = 2, le système ne trouve pas le fichier spécifié. Obtenir cette erreur.
Gentleman
27

.jar n'est pas exécutable. Instanciez des classes ou appelez n'importe quelle méthode statique.

EDIT: Ajoutez une entrée Main-Class lors de la création d'un JAR.

> p.mf (contenu de 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");
  }
}

Utilisez la classe Process et ses méthodes,

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
la source
1
Je pense que l'idée est que, étant donné l'accès à un fichier jar, comment l'ajouter au classpath afin d'en charger les classes.
Jherico
1
Remarque: cela ne fonctionne que parce que vous avez la corbeille java dans votre PATH, ce n'est pas le cas pour l'installation Windows par défaut
poussma
@AVD: où doit-on conserver le fichier A.jar?
logan
1
@logan - Dans un répertoire où vous chargez un programme.
adatapost le
Cette approche créera-t-elle un nouveau processus JVM ou utilisera-t-elle l'existant?
RahulDeep Attri
17

J'espère que cela t'aides:

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
la source
0

Si le fichier jar est dans votre chemin de classe et que vous connaissez sa classe Main, vous pouvez simplement appeler la classe principale. En utilisant DITA-OT comme exemple:

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

Notez que cela obligera le jar subordonné à partager de l'espace mémoire et un chemin de classe avec votre jar, avec tout le potentiel d'interférence que cela peut provoquer. Si vous ne voulez pas que ces choses soient polluées, vous avez d'autres options, comme mentionné ci-dessus - à savoir:

  • créez un nouveau ClassLoader avec le pot à l'intérieur. C'est plus sûr; vous pouvez au moins isoler les connaissances du nouveau fichier jar vers un chargeur de classe principal si vous concevez les choses en sachant que vous utiliserez des fichiers alien. C'est ce que nous faisons dans ma boutique pour notre système de plugins; l'application principale est un minuscule shell avec une fabrique ClassLoader, une copie de l'API et la connaissance que l'application réelle est le premier plugin pour lequel elle devrait construire un ClassLoader. Les plugins sont une paire de jars - interface et implémentation - qui sont compressés ensemble. Les ClassLoaders partagent tous toutes les interfaces, tandis que chaque ClassLoader n'a connaissance que de sa propre implémentation. La pile est un peu complexe, mais elle passe tous les tests et fonctionne à merveille.
  • use Runtime.getRuntime.exec(...)(qui isole complètement le fichier jar, mais a les pièges normaux «trouver l'application», «échapper à vos chaînes», «WTF spécifique à la plate-forme» et «OMG System Threads» lors de l'exécution des commandes système.
Fordi
la source
0

Ce qui suit fonctionne en démarrant le fichier jar avec un fichier de commandes, au cas où le programme s'exécuterait de manière autonome:

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

Dans le batchfile.bat, nous pouvons dire:

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

Si vous êtes java 1.6, les opérations suivantes peuvent également être effectuées:

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
la source
4
Je ne pense pas que cela réponde à la question du PO
Sri Harsha Chilakapati