A Java code-generation library that bridges C/C++ native code to JVM platforms — desktop, mobile, and web.
- Overview
- How It Works
- Supported Targets
- Code Block Convention
- WebIDL Bindings
- IDLBase API
- Requirements
- Getting Started
- Libraries Using jParser
- License
Inspired by gdx-jnigen, jParser lets you embed native C/C++ code directly inside Java source files using annotated comment blocks. Each block is translated into target-specific Java source code, enabling a single lib-base module to produce separate outputs for JNI (desktop & mobile), FFM (desktop, Java 22+), and TeaVM (web via JS/WASM).
For web targets, jParser uses Emscripten to compile C/C++ into JS/WASM and TeaVM to generate the corresponding Java-to-JavaScript bridge via @JSBody annotations.
jParser consists of two main stages:
Reads the hand-written Java source in the lib-base module — which contains embedded native code blocks — and generates platform-specific Java source for each target:
| Output Module | Target | Description |
|---|---|---|
lib-core |
JNI | Generated JNI Java for desktop & mobile |
lib-teavm |
TeaVM | Generated @JSBody-annotated Java for web |
lib-desktop-ffm |
FFM | Generated FFM Java for desktop (Java 22+) |
Compiles the C/C++ source into platform-specific native libraries:
| Platform | Toolchain |
|---|---|
| Windows | MinGW64 or MSVC |
| Linux | GCC / G++ |
| macOS | Xcode CLI tools |
| Android | Android NDK |
| Web | Emscripten SDK |
| Target | Bridge | Platforms | Java Version |
|---|---|---|---|
| JNI | Java Native Interface | Windows, Linux, macOS, Android | 8+ |
| FFM | Foreign Function & Memory API | Windows, Linux, macOS | 22+ |
| TeaVM | JavaScript / WASM | Web browsers | 11+ |
In lib-base Java source files, native code is embedded via annotated comment blocks. jParser reads these blocks and generates the appropriate code for each target.
public class MyLib extends IDLBase {
// TeaVM replacement — generates @JSBody-annotated method for web
/*[-TEAVM;-REPLACE]
@org.teavm.jso.JSBody(params = {"this_addr"},
script = "var jsObj = [MODULE].wrapPointer(this_addr, [MODULE].MyType);"
+ "return jsObj.getValue();")
private static native int internal_native_getValue(int this_addr);
*/
// JNI native code block — compiled into C++ for desktop & mobile
/*[-JNI;-NATIVE]
MyType* obj = (MyType*)this_addr;
return obj->getValue();
*/
private static native int internal_native_getValue(long this_addr);
}| Command | Description |
|---|---|
-NATIVE |
Inline C/C++ code compiled for the target |
-ADD |
Adds code to the generated output |
-ADD_RAW |
Adds raw code without processing |
-REMOVE |
Removes code from the generated output |
-REPLACE |
Replaces the following method with the block content |
-REPLACE_BLOCK |
Replaces the following code block |
-IDL_SKIP |
Placed on a class comment to skip IDL generation for that class |
To reduce the effort of manually porting each method, jParser supports Emscripten WebIDL. Define a .idl file and jParser automatically generates binding code for all targets.
interface NormalClass {
void NormalClass();
long addIntValue(long value1, long value2);
static long subIntValue(long value1, long value2);
attribute long intValue;
attribute float floatValue;
};This generates fully working Java classes with native bindings for JNI, FFM, and TeaVM — no manual glue code required.
- IDL helper classes (
IDLInt,IDLIntArray, etc.) let you pass primitive pointers to C++. They work across Emscripten, desktop, and mobile. - C++ enums are converted into Java enums, each carrying the integer value from native code.
[Value]methods return a cached copy of the object. The cache is overwritten on each call — do not retain references.[NoDelete]classes should not havedispose()called. All other classes require explicit disposal.
Every native class extends IDLBase, which provides common memory-management functionality.
Important: jParser does not automatically dispose C++ objects. You must call
dispose()when you're done with an object to free native memory. Only objects you create or explicitly own require disposal. Creating and disposing native objects is expensive — avoid doing it every frame.
| Method | Description |
|---|---|
ClassName.native_new() |
Creates an empty instance without native data |
ClassName.NULL |
Returns a NULL instance — use instead of Java null for native parameters |
dispose() |
Deletes the native instance (only if owned) |
isDisposed() |
Checks whether the native instance has been disposed |
native_setVoid(...) |
Sets an integer or long memory address |
native_reset() |
Resets the instance to default state |
native_takeOwnership() |
Takes ownership, enabling dispose() to delete the object |
native_releaseOwnership() |
Releases ownership, preventing dispose() from deleting |
native_hasOwnership() |
Checks whether you own the native instance |
native_copy(...) |
Copies memory address and native data from another instance |
The
native_prefix is used to avoid naming conflicts with C/C++ methods.
| Requirement | Purpose |
|---|---|
| JDK 11+ | Building jParser tool modules |
| JDK 22+ (25 recommended) | FFM modules and FFM-based apps |
| MinGW64 or Visual Studio C++ | Windows native builds |
| GCC / G++ | Linux native builds |
| Xcode CLI tools | macOS native builds |
| Emscripten SDK | Web builds (JS/WASM) |
Windows (MSVC): Ensure
vcvarsall.batis on your systemPATH. It is typically located at:C:\Program Files\Microsoft Visual Studio\[Year]\[Edition]\VC\Auxiliary\Build\
For a complete working example, refer to the examples/TestLib module.
jParser projects follow a strict -base / -build / -core / -teavm convention:
| Module Suffix | Purpose |
|---|---|
lib-base |
Hand-written Java source with embedded native code blocks |
lib-build |
Build entry point — configures IDL, targets, runs generation + compilation |
lib-core |
Generated JNI Java output (do not hand-edit) |
lib-teavm |
Generated TeaVM Java output (do not hand-edit) |
lib-desktop-ffm |
Generated FFM Java output (do not hand-edit) |
lib-desktop-jni |
Bundles JNI-compiled native libraries into a JAR |
lib-android |
Android-specific packaging |
# 1. Build idl-helper (required once)
./gradlew :idl-helper:idl-helper-build:idl_helper_build_project_jni_windows64
# 2. Generate code + compile native library
./gradlew :examples:TestLib:lib:lib-build:TestLib_build_project_jni_windows64
# 3. Run the desktop app
./gradlew :examples:TestLib:app:desktop-jni:TestLib_run_app_desktopReplace
windows64withlinux64,mac64, ormacArmfor other platforms. Replacejniwithffmfor Foreign Function & Memory API targets.
| Library | Description | Status |
|---|---|---|
| jWebGPU | WebGPU bindings for Java | Active |
| xImGui | Dear ImGui bindings for Java | Active |
| xJolt | Jolt Physics bindings for Java | Active |
| xLua | Lua bindings for Java | Active |
| xBullet | Bullet Physics bindings for Java | Active |
| gdx-box2d | Box2D bindings for libGDX | Inactive |
| gdx-physx | PhysX bindings for libGDX | Inactive |
jParser is licensed under the Apache License 2.0.