Execute outro jar em um programa Java

115

Eu escrevi vários aplicativos Java simples chamados A.jar, B.jar.

Agora, eu quero escrever um programa GUI java para que o usuário possa pressionar o botão A para executar A.jar e o botão B para executar B.jar.

Também quero gerar os detalhes do processo de tempo de execução no meu programa GUI.

Alguma sugestão?

Winsontan520
fonte
31
Não sei por que isso foi rejeitado. Explique a ele por que suas suposições podem estar erradas, mas não vote contra a pergunta.
William Brendel
-1 terminologia Java básica não é usada corretamente e a pergunta é muito vaga e deixa muito para adivinhar. Considere reformular sua pergunta com mais detalhes ou simplesmente leia sobre o classpath Java e outros princípios básicos primeiro.
topchef
21
@grigory: Veja, isso é o que você deveria ter perguntado em primeiro lugar, em vez de downvoting imediatamente. Downvoting sem mesmo pedir mais informações não adianta nada ...
William Brendel
4
@William, desculpe por apertar o botão alguns segundos depois de você. Eu me reservo o direito de votar contra com comentários subsequentes. É frustrante ver perguntas feitas sem preparação básica e / ou esforço para entender ou apresentar o problema. Votar é como uma gorjeta em um restaurante para mim: você dá mais ou menos 12% do padrão dependendo da qualidade do serviço. Então, vamos concordar em discordar aqui.
topchef
1
@topchef Estou 11 anos atrasado para isso, mas você diz "É frustrante ver perguntas feitas sem uma preparação básica ...". Então ajude a consertar. Explique por que você votou negativamente. Do contrário, você não está ajudando em nada o problema.
tylerr147

Respostas:

63

Se bem entendi, parece que você deseja executar os jars em um processo separado de dentro de seu aplicativo GUI java.

Para fazer isso, você pode 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();

É sempre uma boa prática armazenar em buffer a saída do processo.

gjrwebber
fonte
21
Esta solução é portátil?
Pacerier
3
obrigado. Eu tentei func exec () com 3 parâmetros, incluindo o parâmetro "dir" e não funciona. Com apenas um, só precisamos colocar os 3 arquivos .jar no mesmo lugar
Duc Tran
Você sabe como obter o Runtimeobjeto desse aplicativo java?
Stommestack
Podemos usar uma versão mais portátil, usando ProcessBuilder?
Anand Rockzz
Não é possível executar o programa "java": erro CreateProcess = 2, O sistema não pode encontrar o arquivo especificado. Obtendo este erro.
Cavalheiro de
27

.jar não é executável. Instancie classes ou faça chamadas para qualquer método estático.

EDIT: Adicionar entrada de classe principal ao criar um JAR.

> p.mf (conteúdo de p.mf)

Classe principal: pk.Test

>Test.java

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

Use a classe Process e seus 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
fonte
1
Acho que a ideia é dar acesso a um jar, como adicioná-lo ao classpath para carregar classes a partir dele.
Jherico
1
Nota: funciona apenas porque você tem o java bin em seu PATH, este não é o caso para a instalação padrão do Windows
poussma
@AVD: onde o arquivo A.jar deve ser mantido?
logan
1
@logan - Em um diretório onde você está carregando um programa.
adatapost
Essa abordagem criará um novo processo JVM ou usará o existente?
RahulDeep Attri
17

Espero que isto ajude:

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

Se o jar estiver em seu classpath e você souber sua classe Main, basta invocar a classe principal. Usando DITA-OT como exemplo:

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

Observe que isso fará com que o jar subordinado compartilhe espaço de memória e um caminho de classe com seu jar, com todo o potencial de interferência que pode causar. Se você não quiser que esse material seja poluído, você tem outras opções, conforme mencionado acima - a saber:

  • crie um novo ClassLoader com o jar nele. Isso é mais seguro; você pode, pelo menos, isolar o conhecimento do novo jar para um carregador de classe central se você arquitetar coisas com o conhecimento de que usará jarros alienígenas. É o que fazemos em minha loja para nosso sistema de plug-ins; o aplicativo principal é um pequeno shell com uma fábrica ClassLoader, uma cópia da API e o conhecimento de que o aplicativo real é o primeiro plug-in para o qual ele deve construir um ClassLoader. Os plug-ins são um par de jars - interface e implementação - que são compactados juntos. Todos os ClassLoaders compartilham todas as interfaces, enquanto cada ClassLoader tem conhecimento apenas de sua própria implementação. A pilha é um pouco complexa, mas passa em todos os testes e funciona perfeitamente.
  • use Runtime.getRuntime.exec(...)(que isola totalmente o jar, mas tem as armadilhas normais de "localizar o aplicativo", "escapar das strings corretamente", "WTF específico da plataforma" e "OMG System Threads" na execução de comandos do sistema.
Fordi
fonte
0

O seguinte funciona iniciando o jar com um arquivo em lote, caso o programa seja executado como um autônomo:

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

No batchfile.bat então podemos dizer:

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

Se você for java 1.6, o seguinte também pode ser feito:

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
fonte
4
Não acho que isso responda à pergunta do OP
Sri Harsha Chilakapati