{"id":15297597,"url":"https://github.com/markusjx/node-java-bridge","last_synced_at":"2026-02-22T19:17:17.047Z","repository":{"id":37080812,"uuid":"360450128","full_name":"MarkusJx/node-java-bridge","owner":"MarkusJx","description":"A bridge between Node.js and Java","archived":false,"fork":false,"pushed_at":"2024-04-21T10:05:46.000Z","size":873,"stargazers_count":115,"open_issues_count":4,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-30T00:31:08.543Z","etag":null,"topics":["electron","hacktoberfest","java","javascript","jni","jvm","nodejs","typescript"],"latest_commit_sha":null,"homepage":"https://markusjx.github.io/node-java-bridge/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MarkusJx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-04-22T08:40:25.000Z","updated_at":"2024-10-19T05:28:36.000Z","dependencies_parsed_at":"2024-03-16T11:29:10.641Z","dependency_job_id":"73c6a3df-ed78-4617-b4b5-75fd6a4d5a5f","html_url":"https://github.com/MarkusJx/node-java-bridge","commit_stats":{"total_commits":164,"total_committers":4,"mean_commits":41.0,"dds":0.4695121951219512,"last_synced_commit":"ec3d822ff6ff6cc9960dc89afd1151e585666cda"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fnode-java-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fnode-java-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fnode-java-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MarkusJx%2Fnode-java-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MarkusJx","download_url":"https://codeload.github.com/MarkusJx/node-java-bridge/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247608151,"owners_count":20965952,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["electron","hacktoberfest","java","javascript","jni","jvm","nodejs","typescript"],"created_at":"2024-09-30T19:18:26.269Z","updated_at":"2026-02-22T19:17:17.015Z","avatar_url":"https://github.com/MarkusJx.png","language":"Rust","readme":"# java-bridge\n\n[![Test](https://github.com/MarkusJx/node-java-bridge/actions/workflows/test.yml/badge.svg)](https://github.com/MarkusJx/node-java-bridge/actions/workflows/test.yml)\n[![Check-style](https://github.com/MarkusJx/node-java-bridge/actions/workflows/check-style.yml/badge.svg)](https://github.com/MarkusJx/node-java-bridge/actions/workflows/check-style.yml)\n\n\u003c!--[![SystemTest](https://github.com/MarkusJx/node-java-bridge/actions/workflows/system_test.yml/badge.svg)](https://github.com/MarkusJx/node-java-bridge/actions/workflows/system_test.yml)--\u003e\n\nA bridge between Node.js programs and Java APIs written in Rust\nusing [napi-rs](https://napi.rs/)\nto provide a fast and memory-safe interface between the two languages.\n\nThe pre-compiled binaries will be provided with the package, the only thing\nyou need to do on your machine is install a Java Runtime Environment (JRE)\nfor this package to use. In contrast to other `node.js \u003c-\u003e java` interfaces,\nthe binary is not hard linked to the JDK it has been compiled with but rather\nloads the jvm native library dynamically when the program first starts up.\n\nThe full documentation of this package is\navailable [here](https://markusjx.github.io/node-java-bridge/).\n\n**NOTE: As of version `2.1.0`, this package has been renamed from `@markusjx/java`\nto `java-bridge`.**\n\n## Installation\n\n```shell\nnpm i java-bridge\n```\n\n_Note: In order to use this package on windows, you'll need to install\nthe [Visual C++ Redistributable for Visual Studio 2015](https://www.microsoft.com/en-gb/download/details.aspx?id=48145)._\n\n## Command line interface\n\nThis module also provides a command line interface that allows you to generate typescript\ndefinitions for your java classes.\nThe command line interface is called `java-ts-definition-generator` and can be installed\nusing `npm install -g java-ts-definition-generator`.\nThe full documentation can be\nfound [here](https://github.com/MarkusJx/java-ts-definition-generator).\n\n## Build instructions\n\n_This is only required for development purposes. When installing the package\nusing `npm i`, you can skip this._\n\nIn order to build this project, you should install\n\n- Node.js\n- npm\n- rustc, the rust compiler\n- cargo\n- Java JDK 8+\n- clang\n\nThen, to build the project, run:\n\n```sh\nnpm install\nnpm run build\n```\n\n## Support Matrix\n\n\u003e _✅ = Pre-compiled binaries are available_\u003cbr\u003e _`-` = Pre-compiled binaries are not\n\u003e available_\n\n| Operating System | i686 | x64 | arm | arm64 |\n| ---------------- | :--: | :-: | :-: | :---: |\n| Linux            |  -   | ✅  |  -  |  ✅   |\n| Windows          |  ✅  | ✅  |  -  |   -   |\n| macOS            |  -   | ✅  |  -  |  ✅   |\n\n### Known working linux distros\n\n| Distro |    Version    |\n| :----: | :-----------: |\n| Ubuntu |  `\u003e= 20.04`   |\n| Debian | `\u003e= bullseye` |\n\n## Usage\n\n### Example: Hello world from Java\n\n```ts\nimport { importClass } from './java-bridge';\n\nconst System = importClass('java.lang.System');\nSystem.out.println('Hello world!');\n```\n\n### Create the JVM\n\nCreate a new Java VM using\nthe [`ensureJvm`](https://markusjx.github.io/node-java-bridge/functions/ensureJvm.html)\nmethod.\nCalling this after the jvm has already been created will do nothing.\nDestroying the jvm manually is not (yet) supported.\n\n#### Create the JVM with no extra options\n\nThis will first search for a suitable `jvm` native library on the system and then\nstart the jvm with no extra options. This is also called when any call to the jvm is made\nbut the jvm is not yet started.\n\n```ts\nimport { ensureJvm } from 'java-bridge';\n\nensureJvm();\n```\n\n#### Create the JVM with extra options\n\nYou can pass extra options to the jvm when creating it, for example requesting a specific\njvm version,\nspecifying the location of the jvm native library or passing additional arguments to the\njvm.\n\n```ts\nimport { ensureJvm, JavaVersion } from 'java-bridge';\n\nensureJvm({\n    libPath: 'path/to/jvm.dll',\n    version: JavaVersion.VER_9,\n    opts: ['-Xms512m', '-Xmx512m'],\n});\n```\n\nAll threads will be attached as daemon threads, allowing the jvm to exit when the main\nthread exits.\nThis behaviour can not be changed, as it may introduce undefined behaviour.\n\nImportant note on jvm options: Different arguments must be parsed as separate strings in\nthe `opts` array.\nOtherwise, the jvm will not be able to parse the arguments correctly.\n\n#### Notes on electron\n\nWhen using this package in a packaged electron application, you should unpack this package\nand\nthe appropriate binaries for your platform into the `app.asar.unpacked` folder. When using\nelectron-builder, you can do this by adding the following to your `package.json`:\n\n```json\n{\n    \"build\": {\n        \"asarUnpack\": [\n            \"node_modules/java-bridge/**\",\n            \"node_modules/java-bridge-*/**\"\n        ]\n    }\n}\n```\n\nAdditionally, you should set the `isPackagedElectron` option to `true` when creating the\njvm:\n\n```ts\nensureJvm({\n    isPackagedElectron: true,\n});\n```\n\nThis option _should_ not have any effect when not using electron or not having the\napplication packaged.\n\n### Inject a JAR into the class path\n\nIn order to import your own classes into the node environment, you need\nto add the JAR file to the class path. You can do that with the\n[`appendClasspath`](https://markusjx.github.io/node-java-bridge/functions/appendClasspath.html)\nor [`classpath.append`](https://markusjx.github.io/node-java-bridge/functions/classpath.append.html)\nmethods. After loading a JAR, you can import classes from it like any other class\nfrom the JVM using [`importClass`](#synchronous-calls)\nor [`importClassAsync`](#asynchronous-calls).\n\n```ts\nimport { appendClasspath } from 'java-bridge';\n\n// Append a single jar to the class path\nappendClasspath('/path/to/jar.jar');\n\n// Append multiple jars to the class path\nappendClasspath(['/path/to/jar1.jar', '/path/to/jar2.jar']);\n```\n\nor\n\n```ts\nimport { classpath } from 'java-bridge';\n\n// Append a single jar to the class path\nclasspath.append('/path/to/jar.jar');\n```\n\n### Synchronous calls\n\nIf you want to use Java APIs in a synchronous way, you can use the synchronous API of this\nmodule.\nAny call to the Java API will be executed in the same thread as your node process so this\nmay cause your program to hang until the execution is finished. But - in contrast to the\nasynchronous API -\nthese calls are a lot faster as no extra threads need to be created/attached to the JVM.\n\nAll synchronous java methods are proceeded with the postfix `Sync`.\nThis means, all methods of a class (static and non-static) are generated twice,\nonce as a synchronous call and once as an asynchronous call.\n\nIf you are looking for asynchronous calls, take a look at the next section.\nIn order to import a class synchronously, you can use\nthe [`importClass`](https://markusjx.github.io/node-java-bridge/functions/importClass.html)\nfunction.\nUsing this method does not affect your ability to call any method of the class\nasynchronously.\n\n```ts\nimport { importClass } from 'java-bridge';\n\n// Import a class\nconst JString = importClass('java.lang.String');\n\n// Create a new instance of the class\nconst str = new JString('Hello World');\n\n// Call a method on the instance\nstr.lengthSync(); // 11\n\n// Supported native types will be automatically converted\n// to the corresponding type in the other language\nstr.toStringSync(); // 'Hello World'\n```\n\n### Asynchronous calls\n\nIf you want to use Java APIs in an asynchronous way, you can use the asynchronous API of\nthis module.\nAny call to the Java API will be executed in a separate thread and the execution will not\nblock your program.\nThis is in general a lot slower as the synchronous API but allows the program to run more\nsmoothly.\n\nIf you want to improve the performance of the asynchronous API, you can force the module\nto attach\nany thread as a daemon thread to the JVM. This allows the program to not constantly attach\nnew threads\nto the JVM as the old ones can be reused and thus improves the performance.\n\nIn order to import a class asynchronously, you can use the\n[`importClassAsync`](https://markusjx.github.io/node-java-bridge/functions/importClassAsync.html)\nfunction.\n\n```ts\nimport { importClassAsync } from 'java-bridge';\n\nconst JString = await importClassAsync('java.lang.String');\n\n// Create a new instance asynchrnously using 'newInstanceAsync'\nconst str = await JString.newInstanceAsync('Hello World');\n\n// Call methods asynchronously\nawait str.length(); // 11\nawait str.toString(); // 'Hello World'\n```\n\n### Setting the number of threads\n\nWhen using asynchronous functions, by default, the number of threads used by these functions\nis determined by the number of physical CPUs available.\nIn order to change this behaviour, set the `JAVA_BRIDGE_THREAD_POOL_SIZE` environment variable\nto the desired amount of threads.\n\nNote: Setting this to a non-numeric value will cause an error to be thrown during startup.\n\n### Implement a Java interface\n\nYou can also implement a Java interface in node.js using the\n[`newProxy`](https://markusjx.github.io/node-java-bridge/functions/newProxy.html) method.\nPlease note that when calling a java method that uses an interface defined by this method,\nyou must call that method using the interface asynchronously as Node.js is single threaded\nand can't wait for the java method to return while calling the proxy method at the same\ntime.\n\n```ts\nimport { newProxy } from 'java-bridge';\n\nconst proxy = newProxy('path.to.MyInterface', {\n    // Define methods...\n});\n\n// Do something with the proxy\ninstance.someMethod(proxy);\n\n// Destroy the proxy\nproxy.reset();\n```\n\n### Redirect the stdout and stderr from the java process\n\nIf you want to redirect the stdout and/or stderr from the java\nprocess to the node.js process, you can use the\n[`enableRedirect`](https://markusjx.github.io/node-java-bridge/functions/stdout.enableRedirect.html)\nmethod.\n\n```ts\nimport { stdout } from 'java-bridge';\n\nconst guard = stdout.enableRedirect(\n    (_, data) =\u003e {\n        console.log('Stdout:', data);\n    },\n    (_, data) =\u003e {\n        console.error('Stderr:', data);\n    }\n);\n```\n\n## Errors\n\nErrors thrown in the java process are returned as `JavaError` objects.\nThese objects contain the error message, the full stack trace (including the java, node\nand rust process) and the java throwable that caused\nthe error. The throwable is only available when the error was thrown in the java process\nand not in the node process and if the call was a synchronous call.\n\nThe throwable can be accessed using the `cause` property of the\n`JavaError` object.\n\n```ts\nimport type { JavaError } from 'java-bridge';\n\ntry {\n    // Call a method that throws an error\n    someInstance.someMethodSync();\n} catch (e: unknown) {\n    const throwable = (e as JavaError).cause;\n    throwable.printStackTraceSync();\n}\n```\n\nIf you want to access the Java throwable from an asynchronous call, you\nneed to enable\nthe `asyncJavaExceptionObjects` [config option](https://markusjx.github.io/node-java-bridge/variables/config.html)\nbefore or while importing the class.\nEnabling this will cause the stack trace of the JavaScript error to be lost.\n\n```ts\nimport { importClass } from 'java-bridge';\n\nconst SomeClass = importClass('path.to.SomeClass', {\n    asyncJavaExceptionObjects: true,\n});\n\ntry {\n    await SomeClass.someMethod();\n} catch (e: unknown) {\n    const throwable = (e as JavaError).cause;\n    throwable.printStackTraceSync();\n}\n```\n\n## Logging\n\nIf you want to enable logging for this module, you need to re-compile the module\nwith the `log` feature. Please install the dependencies listed in the\n[build section](#build-instructions) and run `npm run build:all` to build the module with\nall features enabled.\n\nLogged events include:\n\n- Class loading\n- Method calls\n- Class instance creation\n- Method and class lookup\n\n**Note:** Logging affects the performance of the module. Thus, it is recommended\nto only enable logging when debugging.\n\nFor further information on how to use the logging feature, please take a look at the\n[logging module documentation](https://markusjx.github.io/node-java-bridge/modules/internal.logging.html).\n\n## Value conversion rules\n\n1. Any basic value such as `string`, `number`, `boolean` or `BigInt` may be passed to\n   methods accepting matching\n   types\n2. `string` values will always be converted to `java.lang.String`\n3. `string` values with just one character may be converted to `char` or `java.lang.Char`\n   if required\n4. Thus, in order to pass a `char` to a java method, use a `string` containing just one\n   character\n5. `number` values will be converted\n   to `int`, `long`, `double`, `float`, `java.lang.Integer`,\n   `java.lang.Long`, `java.lang.Double` or `java.lang.Float` depending on the type the\n   java function to call requires\n6. `boolean` values will be converted to either `boolean` or `java.lang.Boolean`\n7. `BigInt` values will be converted to either `long` or `java.lang.Long`\n8. Arrays will be converted to java arrays. Java arrays may only contain a single value\n   type, therefore the type of\n   the first element in the array will be chosen as the array type, empty arrays need no\n   conversions.\n9. `java.lang.String` values will be converted to `string`\n10. `int`, `double`, `float`, `java.lang.Integer`, `java.lang.Double` or `java.lang.Float`\n    values will be converted to `number`\n11. `long` or `java.lang.Long` values will always be converted to `BigInt`\n12. `boolean` or `java.lang.Boolean` values will be converted to `boolean`\n13. `char` or `java.lang.Character` values will be converted to `string`\n14. Java arrays will be converted to javascript arrays, applying the rules mentioned above\n    except\n15. Byte arrays will be converted to `Buffer` and vice-versa\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusjx%2Fnode-java-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkusjx%2Fnode-java-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusjx%2Fnode-java-bridge/lists"}