Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

## Unreleased

## [4.4.0] 2025-02-07

- Add `timeout` and `killSignal` run options
- Add `windowsHide` (default: true) to allow to show window if `windowHide: true` is sent

## [4.3.3] 2025-02-03

Expand Down
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Example: `["-Xms256m", "--someflagwithvalue myVal", "-c"]`
| javaArgs | List of arguments for JVM only, not the JAR or the class | `[]` | `['--add-opens=java.base/java.lang=ALL-UNNAMED']` |
| [windowsVerbatimArguments](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) | No quoting or escaping of arguments is done on Windows. Ignored on Unix. This is set to true automatically when shell is specified and is CMD. | `true` | `false` |
| [windowless](https://docs.oracle.com/en/java/javase/17/docs/specs/man/java.html#:~:text=main()%20method.-,javaw,information%20if%20a%20launch%20fails.) | If windowless is true, JavaCaller calls javaw instead of java to not create any windows, useful when using detached on Windows. Ignored on Unix. | false | true
| [windowsHide](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) | On Windows, hide the subprocess console window that would normally be created. Set to `false` if you need Java UI dialogs to be visible (e.g., print dialogs). Ignored on Unix. | `true` | `false`
| [timeout](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) | In milliseconds the maximum amount of time the process is allowed to run. | `undefined` | `1000`
| [killSignal](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options) | The signal value to be used when the spawned process will be killed by timeout or abort signal. | `SIGTERM` | `SIGINT`

Expand Down Expand Up @@ -149,6 +150,23 @@ const java = new JavaCaller({
const { status, stdout, stderr } = await java.run(['--sleep'], { windowless: true });
```

Call java process with visible windows (e.g., for print dialogs)

```javascript
const java = new JavaCaller({
classPath: 'test/java/dist',
mainClass: 'com.nvuillam.javacaller.JavaCallerTester'
});
// Set windowsHide to false to allow Java UI dialogs to be visible
const { status, stdout, stderr } = await java.run([], { windowsHide: false });
```

When using CLI mode with `--no-windows-hide` flag:

```bash
node index.js --no-windows-hide
```

You can see **more examples in** [**test methods**](https://github.com/nvuillam/node-java-caller/blob/master/test/java-caller.test.js)

## TROUBLESHOOTING
Expand Down
13 changes: 12 additions & 1 deletion lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,18 @@ class JavaCallerCli {
const java = new JavaCaller(this.javaCallerOptions);
const args = [...process.argv];
args.splice(0, 2);
const { status } = await java.run(args);

// Parse --no-windows-hide flag (remove all occurrences)
const runOptions = {};
const filteredArgs = args.filter(arg => {
if (arg === '--no-windows-hide') {
runOptions.windowsHide = false;
return false; // Remove from args
}
return true; // Keep in args
});

const { status } = await java.run(filteredArgs, runOptions);
process.exitCode = status;
}
}
Expand Down
7 changes: 7 additions & 0 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ export interface JavaCallerRunOptions {
* @default "SIGTERM"
*/
killSignal?: number | NodeJS.Signals;

/**
* On Windows, hide the subprocess console window that would normally be created.
* This option is ignored on Unix.
* @default true
*/
windowsHide?: boolean;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/java-caller.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ class JavaCaller {
cwd: javaExeToUse === "java" || javaExeToUse === "javaw" ? runOptions.cwd : undefined,
env: Object.assign({}, process.env),
stdio: this.output === "console" ? "inherit" : runOptions.detached ? "ignore" : "pipe",
windowsHide: true,
windowsHide: runOptions.windowsHide !== undefined ? runOptions.windowsHide : true,
windowsVerbatimArguments: runOptions.windowsVerbatimArguments,
};
if (javaExeToUse.includes(" ")) {
Expand Down
47 changes: 47 additions & 0 deletions test/java-caller.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,36 @@ describe("Call with classes", () => {
checkStatus(0, status, stdout, stderr);
});

it("should call JavaCallerTester.class with windowsHide set to false", async () => {
const java = new JavaCaller({
classPath: 'test/java/dist',
mainClass: 'com.nvuillam.javacaller.JavaCallerTester'
});
const { status, stdout, stderr } = await java.run([], { windowsHide: false });
checkStatus(0, status, stdout, stderr);
checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr);
});

it("should call JavaCallerTester.class with windowsHide explicitly set to true", async () => {
const java = new JavaCaller({
classPath: 'test/java/dist',
mainClass: 'com.nvuillam.javacaller.JavaCallerTester'
});
const { status, stdout, stderr } = await java.run([], { windowsHide: true });
checkStatus(0, status, stdout, stderr);
checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr);
});

it("should call JavaCallerTester.class with default windowsHide (should be true)", async () => {
const java = new JavaCaller({
classPath: 'test/java/dist',
mainClass: 'com.nvuillam.javacaller.JavaCallerTester'
});
const { status, stdout, stderr } = await java.run([]);
checkStatus(0, status, stdout, stderr);
checkStdOutIncludes(`JavaCallerTester is called !`, stdout, stderr);
});


it("should call JavaCallerTester.class with proper stdout encoding", async () => {
const java = new JavaCaller({
Expand Down Expand Up @@ -188,6 +218,23 @@ describe("Call with classes", () => {
await javaCli.process();
});

it("should use JavaCallerCli with --no-windows-hide flag", async () => {
// Save original argv
const originalArgv = process.argv;

// Mock process.argv to include --no-windows-hide
process.argv = ['node', 'script.js', '--no-windows-hide'];

try {
const javaCli = new JavaCallerCli("examples/cli_app/lib");
await javaCli.process();
checkStatus(0, process.exitCode);
} finally {
// Restore original argv
process.argv = originalArgv;
}
});

it("Should work with an absolute path", async () => {
const absolutePath = path.join(process.cwd(), "test/java/jar/JavaCallerTesterRunnable.jar");

Expand Down
Loading