It is a bit strange but you can run the second program without forking it. Just calling the main method in it. So forget the runtime section and do this:
sam2.main(new String[0]);
Of course this way you must compile sam2 at compile time
Answer from András Tóth on Stack OverflowIt is a bit strange but you can run the second program without forking it. Just calling the main method in it. So forget the runtime section and do this:
sam2.main(new String[0]);
Of course this way you must compile sam2 at compile time
Each process needs to be allowed to run and finish. You can use Process#waitFor for this purpose. Equally, you need to consume any output from the process at the same time. waitFor will block so you will need use a Thread to read the input (and if you need to, write output to the process)
Depending on the location of the java/class file, you may also need to specify a starting folder from which the execution of the process can start.
Most of this significantly easier using ProcessBuilder
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class CompileAndRun {
public static void main(String[] args) {
new CompileAndRun();
}
public CompileAndRun() {
try {
int result = compile("compileandrun/HelloWorld.java");
System.out.println("javac returned " + result);
result = run("compileandrun.HelloWorld");
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
public int run(String clazz) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("java", clazz);
pb.redirectError();
pb.directory(new File("src"));
Process p = pb.start();
InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
consumer.start();
int result = p.waitFor();
consumer.join();
System.out.println(consumer.getOutput());
return result;
}
public int compile(String file) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("javac", file);
pb.redirectError();
pb.directory(new File("src"));
Process p = pb.start();
InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
consumer.start();
int result = p.waitFor();
consumer.join();
System.out.println(consumer.getOutput());
return result;
}
public class InputStreamConsumer extends Thread {
private InputStream is;
private IOException exp;
private StringBuilder output;
public InputStreamConsumer(InputStream is) {
this.is = is;
}
@Override
public void run() {
int in = -1;
output = new StringBuilder(64);
try {
while ((in = is.read()) != -1) {
output.append((char) in);
}
} catch (IOException ex) {
ex.printStackTrace();
exp = ex;
}
}
public StringBuilder getOutput() {
return output;
}
public IOException getException() {
return exp;
}
}
}
Now obviously, you should check the return results of the processes, and may be produce a better mechanism for interacting with the processes, but that's the basic idea...
How do I run a .java file from another .java file?
How to run a java program from another java program? - Stack Overflow
How to run a .java program from another .java program? - Stack Overflow
How to call a java program from another java program? - Stack Overflow
Videos
I have a Java program that takes user input from the console. Based on user input, one of two .java files in the same package need to be executed. I've already tried:
try {
// Command to create an external process
String command = "C:\\Users\\myname\\eclipseworkspace\\pr\\src\\myPackage\\ViewCustomers.java";
// Running the above command
Runtime run = Runtime.getRuntime();
Process proc = run.exec(command);
} catch (IOException e){
e.printStackTrace();
}
but this gives Cannot run program ... CreateProcess error=193, %1 is not a valid Win32 application.
I know this should be possible, but I can't remember how to do it and my research is only turning up results on how to run programs from the command line, which is not what I need. How can I do this?
Thanks for any help, I really appreciate it.
Using ProcessBuilder.The following is a reference,maybe not work.
ProcessBuilder pb=new ProcessBuilder("java","-jar","Test3.jar");
pb.directory(new File("F:\\dist"));
Map<String,String> map=pb.environment();
Process p=pb.start();
- Create a runnable jar.
- call the runnable jar on button click.
- Exit from the current program.
First, compile your code. I do not think you really want to compile class B from class A as you have written. This almost does not make any sense.
Now, since both are java classes you can just call methods of one class from another directly. If however your really mean that 2 classes are independent programs, so that each one has its own main method you can run one application from another using either Runtime.getRuntime().exec(...) or using ProcessBuilder.
Please pay attention on words really I wrote. I am pretty sure you do not want to call one java program from another. Most chances are that you want to call methods of one class from another, so do this.
@AlexR: IMO this is a valid scenario. Let's assume you want to upload a code from some where and then execute it, and validate the output.
Try using the below mentioned code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class A {
public static void main(String[] args) {
try {
Process processCompile = Runtime.getRuntime().exec("javac B.java");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Process processRun = null;
try {
processRun = Runtime.getRuntime().exec("java B");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
printLines(" stdout:", processRun.getInputStream());
printLines(" stderr:", processRun.getErrorStream());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void printLines(String name, InputStream ins) throws Exception {
String line = null;
BufferedReader in = new BufferedReader(new InputStreamReader(ins));
while ((line = in.readLine()) != null) {
System.out.println(name + " " + line);
}
}
}
Try to set to java process you're launching the correct working directory and then set the related classpath.
This should help.
Update
I suggest to use the method Runtime.getRuntime().exec(String command, String[] envp, File dir).
Last parameter dir is the process working directory.
The Problem here is you are passing argument
./Main.java
instead, you should pass Main.java as an argument else you need to change your getProgramName() method to return the Class name correctly.
Which will let you compile the program perfectly with javac command but problem happens when you need to run the program because that command should be
java Main
whereas you are trying to execute
java ./Main
You're trying to execute "C:/". You'll want to execute something like:
"javaw.exe d:\\somejavaprogram\\program.jar"
Notice the path separators.
I'm assuming this is for an ad-hoc project, rather than something large. However, for best practice running external programs from code:
- Don't hardcode the executable location, unless you're certain it will never change
- Look up directories like %windir% using System.getenv
- Don't assume programs like javaw.exe are in the search path: check them first, or allow the user to specify a location
- Make sure you're taking spaces into account:
"cmd /c start " + myProgwill not work if myProg is"my program.jar".
You can either launch another JVM (as described in detail in other answers). But that is not a solution i would prefer.
Reasons are:
- calling a native program from java is "dirty" (and sometimes crashes your own VM)
- you need to know the path to the external JVM (modern JVMs don't set JAVA_HOME anymore)
- you have no control on the other program
Main reason to do it anyway is, that the other application has no control over your part of the program either. And more importantly there's no trouble with unresponsive system threads like the AWT-Thread if the other application doesn't know its threading 101.
But! You can achieve more control and similar behaviour by using an elementary plugin technique. I.e. just call "a known interface method" the other application has to implement. (in this case the "main" method).
Only it's not quite as easy as it sounds to pull this off.
- you have to dynamically include required jars at runtime (or include them in the classpath for your application)
- you have to put the plugin in a sandbox that prevents compromising critical classes to the other application
And this calls for a customized classloader. But be warned - there are some well hidden pitfalls in implementing that. On the other hand it's a great exercise.
So, take your pick: either quick and dirty or hard but rewarding.
I have modified the code to include some checks:
public class Laj {
private static void printLines(String name, InputStream ins) throws Exception {
String line = null;
BufferedReader in = new BufferedReader(
new InputStreamReader(ins));
while ((line = in.readLine()) != null) {
System.out.println(name + " " + line);
}
}
private static void runProcess(String command) throws Exception {
Process pro = Runtime.getRuntime().exec(command);
printLines(command + " stdout:", pro.getInputStream());
printLines(command + " stderr:", pro.getErrorStream());
pro.waitFor();
System.out.println(command + " exitValue() " + pro.exitValue());
}
public static void main(String[] args) {
try {
runProcess("javac Main.java");
runProcess("java Main");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here is the Main.java:
public class Main {
public static void main(String[] args) {
System.out.println("ok");
}
}
When everything is fine, it just works:
alqualos@ubuntu:~/tmp$ java Laj
javac Main.java exitValue() 0
java Main stdout: ok
java Main exitValue() 0
Now, for example, if I have some error in Main.java:
alqualos@ubuntu:~/tmp$ java Laj
javac Main.java stderr: Main.java:3: package Systems does not exist
javac Main.java stderr: Systems.out.println("ok");
javac Main.java stderr: ^
javac Main.java stderr: 1 error
javac Main.java exitValue() 1
java Main stdout: ok
java Main exitValue() 0
It still prints "ok" because the previously compiled Main.class is still there, but at least you can see what exactly is happening when your processes are running.
You also need to
pro2.waitFor();
because executing that process will take some time and you can't take the exitValue() before the process has finished.