How to Compile Java Program from another Java Program

Introduction

Have you ever wondered if one Java program can execute another Java program? We can use Runtime.exec(String cmd) to issue commands to the underlying operating system. We will use the same approach to execute one Java program through another.

Compile Java Program from another Java Program

Let’s write a simple Java program that will be compiled and run from another Java program.


package com.journaldev.files;

public class Test {

    public static void main(String[] args) {
        System.out.println("Start");
        for(String str : args){
            System.out.println(str);
        }
    }
}
  

Here is the other program where I am compiling and running the Test class.


package com.journaldev.files;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class CompileRunJavaProgram {

    public static void main(String[] args) {
        try {
            runProcess("pwd");
            System.out.println("**********");
            runProcess("javac -cp src src/com/journaldev/files/Test.java");
            System.out.println("**********");
            runProcess("java -cp src com/journaldev/files/Test Hi Pankaj");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void printLines(String cmd, InputStream ins) throws Exception {
        String line = null;
        BufferedReader in = new BufferedReader(new InputStreamReader(ins));
        while ((line = in.readLine()) != null) {
            System.out.println(cmd + " " + 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());
    }
}
  

Notice the Difference in Commands

Notice the difference in javac and java commands. We need to do this because Eclipse working directory is the project root directory but my classes source directory is src.

Here is the output produced when running the above program from Eclipse:


pwd stdout: /Users/pankaj/Documents/eclipse-workspace/JavaExceptions
pwd exitValue() 0
**********
javac -cp src src/com/journaldev/files/Test.java exitValue() 0
**********
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Start
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Hi
java -cp src com/journaldev/files/Test Hi Pankaj stdout: Pankaj
java -cp src com/journaldev/files/Test Hi Pankaj exitValue() 0
  

Making Compile Java Program Platform Independent

The above program works fine in Unix systems but will not work in Windows systems because Windows file separators differ from Unix file separators. To make the program platform independent, we can pass commands as arguments to the main function.


public static void main(String[] args) {
    try {
        if(args.length < 2) throw new Exception("Mandatory Arguments missing");
        runProcess(args[0]);
        runProcess(args[1]);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
  

We can also use File.separator to create commands in a platform-independent way. Here’s an example:


String separator = File.separator;
System.out.println("File Separator = " + separator);

separator = System.getProperty("file.separator");
System.out.println("File Separator = " + separator);

runProcess("javac -cp src src" + separator + "com" + separator + "journaldev" + separator + "files" + separator + "Test.java");
System.out.println("**********");
runProcess("java -cp src com" + separator + "journaldev" + separator + "files" + separator + "Test Hi Pankaj");
  

You will get the same output as before.

Conclusion for Compile Java Program

Using the Runtime.exec method enables us to execute one Java program using another, making it a versatile tool for automating tasks or creating dynamic program workflows. The printLines() and runProcess() methods used in this example are adapted from another post and provide a structured way to handle process execution and output. This approach can also be made platform independent by incorporating File.separator or System.getProperty("file.separator"), ensuring compatibility across different operating systems like Windows, Linux, and macOS without additional modifications.