Ejecuta otro jar en un programa Java

115

Había escrito varias aplicaciones Java sencillas denominadas A.jar, B.jar.

Ahora quiero escribir un programa java GUI para que el usuario pueda presionar el botón A para ejecutar A.jar y el botón B para ejecutar B.jar.

También quiero generar el detalle del proceso en tiempo de ejecución en mi programa GUI.

¿Cualquier sugerencia?

winsontan520
fuente
31
No estoy seguro de por qué se votó en contra. Explíquele por qué sus suposiciones pueden estar equivocadas, pero no rechace la pregunta.
William Brendel
-1 La terminología básica de Java no se usa correctamente y la pregunta es muy vaga y deja mucho para adivinar. Considere reformular su pregunta con más detalles o simplemente lea primero sobre la ruta de clases de Java y otros conceptos básicos.
topchef
21
@grigory: Mira, eso es lo que deberías haber preguntado en primer lugar, en lugar de votar en contra de inmediato. Votar en contra sin siquiera pedir más información no sirve de nada ...
William Brendel
4
@William, perdón por presionar el botón unos segundos más tarde de lo que lo hizo. Me reservo el derecho a votar en contra con comentarios posteriores. Es frustrante ver preguntas formuladas sin una preparación básica y / o esfuerzo para comprender o presentar el problema. Para mí, votar es como una propina en un restaurante: das más o menos del 12% estándar dependiendo de la calidad del servicio. Así que aceptemos estar en desacuerdo aquí.
topchef
1
@topchef Llego 11 años tarde para esto, pero dices "Es frustrante ver preguntas hechas sin una preparación básica ...". Entonces ayude a arreglarlo. Explica por qué votaste en contra. De lo contrario, no estará ayudando en absoluto al problema.
tylerr147

Respuestas:

63

Si lo entiendo correctamente, parece que desea ejecutar los archivos jar en un proceso separado desde dentro de su aplicación GUI de Java.

Para hacer esto puedes usar:

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

Siempre es una buena práctica almacenar en búfer la salida del proceso.

gjrwebber
fuente
21
¿Es esta solución portátil?
Pacerier
3
Gracias. Probé exec () func con 3 parámetros, incluido el parámetro "dir" y no funciona. Con solo uno, solo necesitamos poner los 3 archivos .jar en el mismo lugar
Duc Tran
¿Sabes cómo obtener el Runtimeobjeto de esa aplicación java?
stommestack
¿Podemos usar una versión más portátil usando ProcessBuilder?
Anand Rockzz
No se puede ejecutar el programa "java": Error CreateProcess = 2, el sistema no puede encontrar el archivo especificado. Obteniendo este error.
Caballero
27

.jar no es ejecutable. Cree instancias de clases o realice llamadas a cualquier método estático.

EDITAR: agregue una entrada de clase principal mientras crea un JAR.

> p.mf (contenido de p.mf)

Clase principal: pk.Test

>Test.java

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

Utilice la clase Process y sus métodos,

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
fuente
1
Creo que la idea es que, dado acceso a un jar, ¿cómo se agrega a la ruta de clases para cargar clases fuera de él?
Jherico
1
Nota: funciona solo porque tiene el contenedor de Java en su PATH, este no es el caso de la instalación predeterminada de Windows
poussma
@AVD: ¿dónde se debe guardar el archivo A.jar?
logan
1
@logan: en un directorio donde está cargando un programa.
adatapost
¿Este enfoque creará un nuevo proceso de JVM o utilizará el existente?
RahulDeep Attri
17

Espero que esto ayude:

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
fuente
0

Si el jar está en su ruta de clases y conoce su clase principal, puede invocar la clase principal. Usando DITA-OT como ejemplo:

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

Tenga en cuenta que esto hará que el jar subordinado comparta espacio de memoria y una ruta de clase con su jar, con todo el potencial de interferencia que puede causar. Si no desea que esas cosas se contaminen, tiene otras opciones, como se mencionó anteriormente, a saber:

  • cree un nuevo ClassLoader con el jar en él. Esto es más seguro; al menos puede aislar el conocimiento del nuevo tarro en un cargador de clases central si diseña las cosas con el conocimiento de que utilizará tarros extraterrestres. Es lo que hacemos en mi tienda para nuestro sistema de complementos; la aplicación principal es un pequeño shell con una fábrica de ClassLoader, una copia de la API y el conocimiento de que la aplicación real es el primer complemento para el que debe construir un ClassLoader. Los complementos son un par de frascos (interfaz e implementación) que se cierran juntos. Todos los ClassLoaders comparten todas las interfaces, mientras que cada ClassLoader solo tiene conocimiento de su propia implementación. La pila es un poco compleja, pero pasa todas las pruebas y funciona a la perfección.
  • use Runtime.getRuntime.exec(...)(que aísla completamente el jar, pero tiene los errores normales de "encontrar la aplicación", "escapar correctamente de las cadenas", "WTF específico de la plataforma" y "OMG System Threads" de ejecutar comandos del sistema.
Fordi
fuente
0

Lo siguiente funciona iniciando el jar con un archivo por lotes, en caso de que el programa se ejecute de forma independiente:

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

En el archivo batchfile.bat podemos decir:

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

Si es java 1.6, también puede hacer lo siguiente:

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
fuente
4
No creo que esto responda a la pregunta del OP
Sri Harsha Chilakapati