{"id":21406507,"url":"https://github.com/forge-srl/jjbridge-api","last_synced_at":"2025-10-27T23:16:25.216Z","repository":{"id":56291491,"uuid":"307292670","full_name":"Forge-Srl/jjbridge-api","owner":"Forge-Srl","description":"JJBridge Api defines a set of interfaces to run JavaScript code from Java.","archived":false,"fork":false,"pushed_at":"2021-09-07T07:23:39.000Z","size":148,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-07T20:21:30.999Z","etag":null,"topics":["java","javascript","jjbridge"],"latest_commit_sha":null,"homepage":"","language":"Java","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/Forge-Srl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-26T07:29:56.000Z","updated_at":"2022-04-05T09:41:34.000Z","dependencies_parsed_at":"2022-08-15T16:10:16.617Z","dependency_job_id":null,"html_url":"https://github.com/Forge-Srl/jjbridge-api","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/Forge-Srl/jjbridge-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Forge-Srl%2Fjjbridge-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Forge-Srl%2Fjjbridge-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Forge-Srl%2Fjjbridge-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Forge-Srl%2Fjjbridge-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Forge-Srl","download_url":"https://codeload.github.com/Forge-Srl/jjbridge-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Forge-Srl%2Fjjbridge-api/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265227898,"owners_count":23731059,"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":["java","javascript","jjbridge"],"created_at":"2024-11-22T16:40:22.006Z","updated_at":"2025-10-27T23:16:20.169Z","avatar_url":"https://github.com/Forge-Srl.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JJBridge Api\n\n[![javadoc](https://javadoc.io/badge2/srl.forge/jjbridge-api/javadoc.svg)](https://javadoc.io/doc/srl.forge/jjbridge-api)\n\n![Build JJBridge Api](https://github.com/Forge-Srl/jjbridge-api/workflows/Build%20JJBridge%20Api/badge.svg?branch=main)\n\nJJBridge is a multi-library project which brings JavaScript execution capabilities to Java.\n\nJJBridge Api defines a standard set of interface for accessing a JavaScript engine from Java.\n\n## Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n  - [Quickstart](#quickstart)\n  - [How it works?](#how-it-works)\n  - [Interacting with the runtime](#interacting-with-the-runtime)\n    - [Primitive types](#primitive-types)\n    - [Objects](#objects)\n    - [Arrays](#arrays)\n    - [Functions](#functions)\n    - [Externals](#externals)\n    - [Scripts and other things](#scripts-and-other-things)\n  - [Debugging with the inspector](#debugging-with-the-inspector)\n- [License](#license)\n\n## Installation\n\nAdd this to your pom.xml:\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003esrl.forge\u003c/groupId\u003e\n  \u003cartifactId\u003ejjbridge-api\u003c/artifactId\u003e\n\u003c/dependency\u003e\n```\n\n**In order to actually execute JavaScript you should also add a JJBridge Engine library.**\n\nHere is a list of the engines currently available for JJBridge:\n- [JJBridge V8 Engine](https://github.com/Forge-Srl/jjbridge-engine-v8) (Available for Linux, Windows, macOS and Android)\n\n## Usage\nThe full javadoc is available at \u003chttps://www.javadoc.io/doc/srl.forge/jjbridge-api/latest/index.html\u003e.\n\n### Quickstart\nAll JavaScript code must run inside a `JSRuntime` instance. Here is an example:\n```java\nclass Example {\n    private static JSEngine engine = new V8Engine(); // or other available engine\n    \n    public static void main(String[] args) {\n        try (JSRuntime runtime = engine.newRuntime()) {\n            // Do JavaScript things here...\n            String script =\n                \"const foo = '25'\\n\" +\n                \"const bar = 33\\n\" +\n                \"const mult = (a, b) =\u003e `${a} x ${b} = ${a * b}`\\n\" +\n                \"mult(foo, bar)\";\n    \n            JSReference resultJSRef = runtime.executeScript(script);\n            JSString resultJSString = runtime.resolveReference(resultJSRef);\n            String result = resultJSString.getValue();\n            System.out.println(result); // Prints \"25 x 33 = 825\"\n        } catch (RuntimeException e) {\n            // handle errors here\n        }\n    }\n}\n```\n\n### How it works?\nA `JSRuntime` is an instance of a JavaScript engine context. It is the single point from which you can execute scripts \nand access JavaScript objects.\n\nAll interactions between JavaScript and Java exploit instances of `JSReference`. A `JSReference` is a lightweight \npointer to a JavaScript object which can be passed in and out of the runtime when needed. References are created as a \nresult of a script execution, as a result of a JavaScript function invocation, accessing a JavaScript object field or\neven directly from the runtime using the `newReference(JSType type)` method.\n\nIf you need to access the actual value pointed by a reference, you must resolve it using the \n`resolveReference(JSReference reference)` method of the runtime. When resolving a reference, you must specify the \nexpected `JSValue` sub-type. `JSValue` sub-types are the following:\n- `JSUndefined`: maps JavaScript `undefined`.\n- `JSNull`: maps JavaScript `null`.\n- `JSBoolean`: maps a JavaScript boolean; allows get/set of the value.\n- `JSNumber`: maps a JavaScript number to a Java double; allows get/set of the value and provides additional utilities \n  for long values.\n- `JSString`: maps a JavaScript string; allows get/set of the value.\n- `JSObject`: maps a JavaScript object; allows get/set of properties/methods.\n- `JSDate`: maps a JavaScript date; allows get/set of the value and properties/methods.\n- `JSArray`: maps a JavaScript array; allows get/set of properties/methods and elements.\n- `JSFunction`: maps a JavaScript function; allows get/set of properties/methods, invocation (both as normal function\n  and as constructor) and change of the actual code to execute.\n- `JSExternal`: this is a special type which allows the runtime to store references to Java objects in JavaScript\n  objects.\n  \n**Using the wrong type may throw an exception.**\n\n### Interacting with the runtime\n#### Primitive types\nWorking with primitive types (booleans, numbers, strings) is pretty straightforward. You can only get and set the value.\n*Dates are objects (because you can access fields and methods), but they also allow getting and setting the value just \nlike primitive types.*\n\nHere is an example with booleans:\n```java\nJSReference ref = runtime.newReference(JSType.Boolean);\nJSBoolean jsBool = runtime.resolveReference(ref);\n\njsBool.setValue(true);\nBoolean b = jsBool.getValue(); // b is true\n\njsBool.setValue(false);\nb = jsBool.getValue(); // b is false\n```\n\nAnd now an example with numbers:\n```java\nJSReference ref = runtime.newReference(JSType.Number);\nJSNumber jsNum = runtime.resolveReference(ref);\n\njsNum.setValue(420.5);\nDouble i = jsInt.getValue(); // i is 420.5\n\njsInt.setValue(-10000009);\ni = jsInt.getValue(); // i is -10000009\n```\n\n#### Objects\nWorking with objects is all about getting and setting properties. Properties can be fields of any type but also methods \n(which are nothing but functions).\n\nHere is an example:\n```java\nJSReference ref = runtime.newReference(JSType.Object);\nJSObject\u003c?\u003e jsObj = runtime.resolveReference(ref);\n\nJSReference field1ref = runtime.newReference(JSType.String);\n((JSString) runtime.resolveReference(field1ref)).setValue(\"foo bar baz\");\njsObj.set(\"field1\", field1ref);\n// now jsObj is {field1: \"foo bar baz\"}\n\njsObj.set(\"field2\", runtime.newReference(JSType.Null));\n// now jsObj is {field1: \"foo bar baz\", field2: null}\n\njsObj.set(\"field3\", runtime.executeScript(\"({inner: 8})\"));\n// now jsObj is {field1: \"foo bar baz\", field2: null, field3: {inner: 8}}\n\nJSReference field3ref = jsObj.get(\"field3\");\nJSObject\u003c?\u003e field3 = runtime.resolveReference(field3ref);\nJSNumber inner = runtime.resolveReference(field3.get(\"inner\"));\nLong i = inner.getLongValue() // i is 8\n```\n\n#### Arrays\nArrays are much like objects, but instead of accessing a property by name, you can access an item by index. *Array are \nalso objects, which means you can access all array properties.*\n\nHere is an example:\n```java\nJSReference ref = runtime.newReference(JSType.Array);\nJSArray\u003c?\u003e jsArray = runtime.resolveReference(ref);\nint size = jsArray.size(); // size is 0\n\njsArray.set(0, runtime.newReference(JSType.Null));\njsArray.set(1, runtime.newReference(JSType.Null));\njsArray.set(2, runtime.executeScript(\"11**4\"));\nsize = jsArray.size(); // size is 3\n\nJSNumber inner = runtime.resolveReference(jsArray.get(2));\nLong i = inner.getLongValue() // i is 14641\n```\n\n#### Functions\nYou can get a function either from a script or accessing an object property. Depending on the function, you can call it\nnormally or as a constructor. *Functions are also objects, which means you can access all function properties.*\n\nHere is an example:\n```java\nJSReference ref = runtime.executeScript(\"(a, b) =\u003e a + b\");\nJSFunction\u003c?\u003e jsFunction = runtime.resolveReference(ref);\n\nJSReference stringRef = runtime.newReference(JSType.String);\n((JSString) runtime.resolveReference(stringRef)).setValue(\"Toc\");\nJSReference resultRef = jsFunction.invoke(ref, stringRef, stringRef);\nString resultString = ((JSString) runtime.resolveReference(resultRef)).getValue(); // resultString is TocToc\n\nJSReference intRef = runtime.newReference(JSType.Number);\n((JSNumber) runtime.resolveReference(intRef)).setLongValue(12L);\nresultRef = jsFunction.invoke(ref, intRef, intRef);\nLong resultInt = ((JSNumber) runtime.resolveReference(resultRef)).getLongValue(); // resultInt is 24\n```\n\nYou can also create a JavaScript function which will execute Java code when invoked:\n```java\nJSReference ref = runtime.newReference(JSType.Function);\nJSFunction\u003c?\u003e jsFunction = runtime.resolveReference(ref);\n\njsFunction.setFunction((JSReference... args) -\u003e {\n    String arg0 = ((JSString) runtime.resolveReference(args[0])).getValue();\n    String arg1 = ((JSString) runtime.resolveReference(args[1])).getValue();\n\n    String result = someObject.someFunction(arg0, arg1); // Do something with the args\n\n    JSReference resultRef = runtime.newReference(JSType.String);\n    ((JSString) runtime.resolveReference(resultRef)).setValue(result);\n    return resultRef; // TIP: if the function is supposed to be void then just return undefined.\n});\n```\n\n#### Externals\nThe external type is a special type useful to store native Java data inside a JavaScript object for later retrieval.\nFrom a JavaScript point of view, external values are indistinguishable from objects, but from a Java point of view they \nstore additional data.\n\nThe usage is pretty much like a primitive type:\n```java\nJSReference ref = runtime.newReference(JSType.External);\nJSExternal\u003cHashMap\u003cString, int[]\u003e\u003e jsExternal = runtime.resolveReference(ref);\n\nHashMap\u003cString, int[]\u003e hashMap = new HashMap\u003c\u003e();\nhashMap.put(\"asd\", new int[] {1, 2});\njsExternal.setValue(hashMap);\nhashMap = null;\n// A reference to the hash map is still present inside the external object, thus we can retrieve it\nhashMap = jsExternal.getValue();\nint[] array = hashMap.get(\"asd\"); // array is [1, 2]\n```\n\n#### Scripts and other things\nAs you have seen from the examples above, to run a script you just need to use `runtime.executeScript(script)` passing \nthe JavaScript code as a `String`. There is a useful variant of this method which also allows to assign a file name to \nthe script; this is useful if you have to debug many scripts in the inspector!\n\nThe result of a script execution is the last expression of the script. For example if the script is:\n```js\nconst defaultName = 'world'\nconst greet = function(name = defaultName) {\n    return {greeting: `Hello ${name}!`}\n}\ngreet('Alice')\n```\nThe result will be the value of the last expression `greet('Alice')` which is the resulting object \n`{greeting: \"Hello Alice!\"}`.\n\n**When you run multiple scripts keep in mind they are isolated, which means a variable defined in one script is not \navailable in a different script.** If you want to share values between scripts you should expose them as references \nwhich will be passed from Java.\n\nThe only exception are the **global variables** of the runtime. A global variable is just a property of the global \nobject which is made accessible to the scripts as a predefined variable. To get the global object use \n`runtime.globalObject()`, then add each variable as a property to this object. Remember to define your global variables \nbefore running a script which use them!\n\nHere is an example:\n```java\nJSReference globRef = runtime.newReference(JSType.Number);\n((JSNumber) runtime.resolveReference(globRef)).setLongValue(21);\nruntime.globalObject().set(\"myGlobVar\", globRef);\n\nJSReference resultRef = runtime.executeScript(\"27 + (myGlobVar * 2)\");\nLong result = ((JSNumber) runtime.resolveReference(resultRef)).getLongValue(); // result is 69\n```\n\nIt is also possible to use different runtime instances at once. **Runtime instances are completely isolated** which \nmeans they don't share memory (even global variables are different). **Never pass/resolve a reference coming from a \nruntime instance with a different one!**; this could lead to an undefined behaviour, most likely an exception to be \nthrown.\n\n### Debugging with the inspector\nJJBridge allows you to debug JavaScript code via the Chrome DevTools Inspector protocol.\nTo enable debugging via the inspector you have to follow these steps:\n1. Create an inspector and attach it to a runtime:\n   ```java\n   // ...\n   JSInspector inspector = engine.newInspector(9090); // use a free port on your machine\n   try (JSRuntime runtime = engine.newRuntime()) {\n       inspector.attach(runtime);\n       \n       // Do JavaScript things here...\n   }\n   // ...\n   ```\n2. Run the app.\n3. Connect to the inspector at `chrome-devtools://devtools/bundled/inspector.html?v8only=true\u0026ws=IP:PORT` where:\n   - `IP` is the IP address of the machine running the code;\n   - `PORT` is the port passed to the inspector (*9090* in the example up here).\n4. Debug :tada:\n\n**Before releasing your app it is recommended to remove all inspector-related code to avoid undesired access to the \nJavaScript code shipped with it.**\n\n## License\n\nSee the [LICENSE](LICENSE.md) file for license rights and limitations (MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforge-srl%2Fjjbridge-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fforge-srl%2Fjjbridge-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fforge-srl%2Fjjbridge-api/lists"}