Uruchom kolejny plik jar w programie Java

115

Napisałem kilka prostych aplikacji Java o nazwach A.jar, B.jar.

Teraz chcę napisać program Java z graficznym interfejsem użytkownika, aby użytkownik mógł nacisnąć przycisk A, aby wykonać A.jar i przycisk B, aby wykonać B.jar.

Chcę również wyprowadzić szczegóły procesu wykonywania w moim programie GUI.

Jakieś sugestie?

winsontan520
źródło
31
Nie jestem pewien, dlaczego głosowanie odrzucono. Wyjaśnij mu, dlaczego jego założenia mogą być błędne, ale nie bagatelizuj pytania.
William Brendel
-1 podstawowa terminologia Java nie jest używana poprawnie, a pytanie jest bardzo niejasne i pozostawia wiele do ponownego zgadnięcia. Rozważ przeformułowanie pytania, dodając więcej szczegółów lub po prostu przeczytaj najpierw o ścieżce klas języka Java i innych podstawach.
topchef
21
@grigory: Widzisz, właśnie o to powinieneś zapytać, zamiast od razu głosować w dół. Głosowanie w dół bez pytania o więcej informacji nic nie da ...
William Brendel
4
@William, przepraszam za naciśnięcie przycisku kilka sekund później niż ty. Zastrzegam sobie prawo do głosowania przeciw z późniejszym komentarzem. Frustrujące jest zadawanie pytań bez podstawowego przygotowania i / lub wysiłku, aby zrozumieć lub przedstawić problem. Głosowanie jest dla mnie jak napiwek w restauracji: dajesz więcej lub mniej niż standardowe 12% w zależności od jakości obsługi. Więc zgódźmy się tutaj nie zgodzić.
topchef
1
@topchef Spóźniłem się o 11 lat, ale mówisz: „To frustrujące, gdy widzę pytania zadawane bez podstawowego przygotowania…”. Następnie pomóż to naprawić. Wyjaśnij, dlaczego przegłosowałeś. W przeciwnym razie w ogóle nie pomagasz w problemie.
tylerr147

Odpowiedzi:

63

Jeśli dobrze rozumiem, wygląda na to, że chcesz uruchomić słoiki w oddzielnym procesie z poziomu aplikacji graficznej w języku Java.

Aby to zrobić, możesz użyć:

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

Zawsze dobrą praktyką jest buforowanie wyniku procesu.

gjrwebber
źródło
21
Czy to rozwiązanie jest przenośne?
Pacerier,
3
dzięki. Próbowałem exec () func z 3 parametrami, w tym parametrem „dir” i nie działa. Mając tylko jeden, musimy tylko umieścić 3 pliki .jar w tym samym miejscu
Duc Tran
Czy wiesz, jak zdobyć Runtimeobiekt tej aplikacji Java?
stommestack
Czy możemy użyć bardziej przenośnej wersji, używając ProcessBuilder?
Anand Rockzz,
Nie można uruchomić programu „java”: błąd CreateProcess = 2, system nie może znaleźć określonego pliku. Pojawia się ten błąd.
Gentleman
27

.jar nie jest wykonywalny. Utwórz instancję klas lub wywołaj dowolną metodę statyczną.

EDYCJA: Dodaj wpis klasy głównej podczas tworzenia pliku JAR.

> p.mf (treść p.mf)

Klasa główna: test pk

>Test.java

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

Użyj klasy Process i jej metod,

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
źródło
1
Myślę, że chodzi o to, że mając dostęp do słoika, jak dodać go do ścieżki klas, aby załadować z niego klasy.
Jherico
1
Uwaga: działa tylko dlatego, że masz bin Java w swojej PATH, tak nie jest w przypadku domyślnej instalacji systemu Windows
poussma
@AVD: gdzie powinien być przechowywany plik A.jar?
logan
1
@logan - w katalogu, w którym ładujesz program.
adatapost
Czy to podejście stworzy nowy proces JVM, czy wykorzysta istniejący?
RahulDeep Attri
17

Mam nadzieję że to pomoże:

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
źródło
0

Jeśli jar znajduje się w Twojej ścieżce klas i znasz jego klasę główną, możesz po prostu wywołać klasę główną. Na przykładzie DITA-OT:

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

Zauważ, że spowoduje to, że podrzędny słoik będzie współdzielił przestrzeń pamięci i ścieżkę klas z twoim słoikiem, z całym potencjałem zakłóceń, które mogą powodować. Jeśli nie chcesz, aby te rzeczy były zanieczyszczone, masz inne opcje, jak wspomniano powyżej - a mianowicie:

  • utwórz nowy ClassLoader z zawartym w nim jar. To jest bezpieczniejsze; możesz przynajmniej wyodrębnić wiedzę nowego słoika do podstawowego modułu ładującego klasy, jeśli projektujesz rzeczy ze świadomością, że będziesz używać słoików obcych. To właśnie robimy w moim sklepie dla naszego systemu wtyczek; główną aplikacją jest malutka powłoka z fabryką ClassLoader, kopią API i wiedzą, że prawdziwa aplikacja jest pierwszą wtyczką, dla której powinna zbudować ClassLoader. Wtyczki to para plików JAR - interfejs i implementacja - które są spakowane razem. Wszystkie ClassLoadery współużytkują wszystkie interfejsy, podczas gdy każdy ClassLoader ma wiedzę tylko o swojej własnej implementacji. Stos jest trochę skomplikowany, ale przechodzi wszystkie testy i działa pięknie.
  • use Runtime.getRuntime.exec(...)(który całkowicie izoluje jar, ale ma normalne pułapki „znajdź aplikację”, „poprawne unikanie ciągów znaków”, „WTF specyficzne dla platformy” i „Wątki systemowe OMG” związane z uruchamianiem poleceń systemowych.
Fordi
źródło
0

Poniższe działa, uruchamiając jar za pomocą pliku wsadowego, w przypadku gdy program działa samodzielnie:

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

W pliku batchfile.bat możemy wtedy powiedzieć:

@echo off
start /min C:\path\to\jarprogram.jar
Dawood Morris
źródło
-3

Jeśli korzystasz z java 1.6, możesz również wykonać następujące czynności:

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
źródło
4
Nie sądzę, żeby to odpowiadało na pytanie OP
Sri Harsha Chilakapati