How to call java file from different directory using nodejs child process

Viewed 274

I am trying to run a java class file from a different directory. However, it always gives the error "Could not find or load main class {dirpath}"

My project directory is as follows:

  - NodeProject
    - code
      - Main.java
      - javaClasses
    - index.js

"code" folder contains java src files, that I take as input from a candidate/user and save it as filename.java and a folder "javaClasses", which should contain the .class file after compilation.
index.js is my entry point which runs via npm start

my index.js code is as follows:

const spawnSync = require("child_process").spawnSync;
const { exec } = require("child_process")
const path = require('path');


let filepath = path.join(__dirname, "code", "Main.java");
let dirpath = path.join(__dirname, "code", "javaClasses");
let folderPath = path.join(__dirname, "code");

const run = async (command, args) => {
    let options = "";


    let output = spawnSync("javac", ["-d", dirpath, filepath]); /// creates Main.class file in javaClasses folder

    exec(`${command} "${args}" | java -cp ${dirpath} Main`, (error, stdout, stderr) =>{
      if (error) {
          console.error(`exec error: ${error}`);
          return;
        }
        console.log(`stdout: ${stdout}`);
        console.error(`stderr: ${stderr}`);
      });

    
    
    
}

let s ="22"
run("printf", [s]);

.class file is succesfully compiled, exec command is giving the error.
I tried replacing dirpath with folderpath where the actual src file is but to no avail.
I saw somewhere to try cd {path} & java Main but it still doesn't work and give the same error.

Also, my src file doesn't have any package import like package code, since i take the whole src file from user input.

Any help will be very much appreciated!.

1 Answers

I am not sure if i understood your problem correctly, but i will give it a try.

If the contents of Main.java looks like this:

public class Main {
    public static void main(String[] a) {
        System.out.println("Hello World");
    }
 }

I don't have any Problem just running this with the code you provided.

The Problem starts if i modify the Main.java to look like this:

public class Main {
    public static void main(String[] a) {
        Echoer e = new Echoer();
        e.setReq("Hello world!");
        System.out.println(e.getRes());
    }
 }

Echoer.java:

public class Echoer {
    private String req = null;
    private String res = null;
    public void setReq(String r) {
       req = new String(r);
       char[] a = r.toCharArray();
       int n = a.length;
       for (int i=0; i<n/2; i++) {
          char t = a[i];
          a[i] = a[n-1-i];
          a[n-i-1] = t;
       }
       res = new String(a);
    }
    public String getRes() {
       return res;
    }
 }

I do get the Error "Could not find or load main class Main", which should be equal to your provided message as dirpath is set to

let filepath = path.join(__dirname, "code", "Main.java");

I assume you want to call some Methods in your Main.java which are defined in another Java File. To achieve this, we need to tell the Java Compiler to compile any Java Files present. I modified the index.js file to look like this

const spawnSync = require("child_process").spawnSync;
const { exec } = require("child_process")
const path = require('path');


let filepath = path.join(__dirname, "code", "*.java");
let dirpath = path.join(__dirname, "code", "javaClasses");
let folderPath = path.join(__dirname, "code");

const run = async (command, args) => {


    let options = "";


    exec(`javac -d ${dirpath} ${filepath}`, (error, stdout, stderr) =>{
        if (error) {
            console.error(`exec error: ${error}`);
            return;
          }
          console.log(`stdout: ${stdout}`);
          console.error(`stderr: ${stderr}`);
          exec(`${command} "${args}" | java -cp ${dirpath} Main`, (error, stdout, stderr) =>{
            if (error) {
                console.error(`exec error: ${error}`);
                return;
              }
              console.log(`stdout: ${stdout}`);
              console.error(`stderr: ${stderr}`);
            });
        });
}

let s ="22"
run("printf", [s]);

This now works with as many .java Files as you like.

Note 1: I did delete the .class Files after every run

Note 2: I did not get it to work with spawnSync

Related