ENGLISH | 中文
Java bindings for Godot.
Built on top of GDExtension and Panama FFI to make Java a first-class citizen in the Godot ecosystem.
Status: 0.1.0 – production-ready with scoped memory management and full GDExtension feature coverage.
Project examples:
In the game engine world, Java is almost always the missing language:
- Unity offers C# as its scripting language — no Java
- Unreal Engine is firmly C++ — no Java
- Godot ships with GDScript and C# — no Java
- Even community-maintained bindings (e.g. godot-kotlin-jvm) target Kotlin or require recompiling the engine
Meanwhile, Java remains one of the most widely used languages on the planet — dominant in enterprise backends, Android development, and large-scale data processing. Millions of developers write Java every day, yet the game engine ecosystem offers them almost nothing.
For teams with an existing Java stack, this is a real gap:
- Their codebase, tools, and engineering practices are all built around Java
- Trying a game engine often means:
- Learning and maintaining a completely different language (C++/GDScript/C#), or
- Building and maintaining a fragile bridge between Java and the engine
godot-java aims to challenge the “no Java in game development” status quo:
- Give Java a first-class seat in the Godot ecosystem
- Let existing Java teams reuse:
- Their language and IDEs (IntelliJ IDEA / Eclipse / VS Code, etc.)
- Their build and dependency tooling (Maven/Gradle)
- Their testing, logging, diagnostics, and CI/CD pipelines
From an engineering point of view, the goals are:
- Provide a natural Java experience (annotations, strong typing, modern FFI)
- Avoid piles of custom JNI glue – lean on Java 25’s Panama FFI instead
This project deliberately targets Java 25+ instead of trying to support older LTS releases like 8/11/17.
There are three main reasons:
-
No legacy baggage
By focusing on a single modern Java version, we keep the codebase clean and straightforward.
There is no need to carry around compatibility layers or branching logic for older JDKs. -
Use the latest language and platform features
We can freely use:- Records, sealed types, pattern matching
- The enhanced
switchexpression andvarwhere it makes sense - The latest
java.lang.foreignPanama FFI APIs
This allows the binding code itself to look and feel like modern Java, not “Java written as if it were C”.
-
Let you fully enjoy modern Java
The idea is to let you write game code while enjoying everything modern Java has to offer:- Expressive language features
- A rich library ecosystem
- A familiar toolchain
Without constantly worrying “will this feature work on some old JDK?”
If you are curious what “Godot + modern Java + Panama FFI” can look like, this project is meant as a clean, modern starting point rather than a legacy SDK that evolved from older Java versions.
Core capabilities currently implemented:
-
Godot GDExtension binding (C API)
- Uses
GDExtensionInterfaceGetProcAddressto dynamically load the Godot API - Models core C structs such as
GDExtensionClassLibraryPtr,GDExtensionPropertyInfo,GDExtensionClassMethodInfo, etc.
- Uses
-
Java 25 Panama FFI integration
- Uses
java.lang.foreign(Linker,FunctionDescriptor,MemorySegment, …) to call into Godot - No custom JNI-based helper library is required
- Uses
-
Annotation-driven class / method / property / signal registration
@GodotClass– declare a Java class that can be instantiated from Godot@GodotMethod– expose a Java method to be called from Godot@Export– export a field to the Godot Inspector withhint/hintStringsupport@Signal– declare and emit Godot signals from Java- APT processor (
godot-java-processor) generates typed dispatch code at compile time (zero runtime reflection in the hot path)
-
APT-compiled typed dispatch (aligned with gdext/Rust architecture)
TypedDispatch_<ClassName>— MethodHandle/VarHandle-based method dispatchPropertyAccess_<ClassName>— VarHandle-based property access for @Export fieldsVirtualDispatch_<ParentClass>— per-parent-class hash maps for virtual method resolution- Reflection fallback when APT data is unavailable
-
Virtual methods and lifecycle callbacks
- Supports all 1144 virtual methods across all Godot classes
- Per-class
get_virtual_funcupcall stubs (lazy, only for overridden methods) - Lifecycle callbacks:
notification_func,to_string_func,reference_func/unreference_func,validate_property_func
-
ptrcall support
- Zero-copy typed pointer dispatch (avoids Variant boxing for method calls)
- RefCounted-aware: uses
ref_get_object/ref_set_objectfor RefPtr parameters - APT-generated MethodHandle dispatch for registered @GodotMethod methods
-
Property system
get_property_list_func— exposes @Export fields to Godot editorproperty_can_revert_func/property_get_revert_func— default value support- Hash collision resolution by StringName pointer comparison
-
Type system and Variant interop
- Java-side types for
Variant,GodotStringName,GodotString,GodotArray,GodotDictionary, etc. - Safe conversions between common Java types and Godot Variants
- Java-side types for
The dispatch architecture is aligned with gdext (the Rust bindings): upcall stubs are created lazily at class registration time, only for methods the user actually overrides. Unimplemented methods return NULL so Godot uses its default C++ implementation.
The annotation processor (godot-java-processor) generates per-class dispatch code at compile time:
TypedDispatch_<ClassName>—MethodHandle/VarHandle-based method dispatch (zero reflection on the hot path)PropertyAccess_<ClassName>—VarHandle-based property access for@ExportfieldsVirtualDispatch_<ParentClass>— per-parent-class hash maps for virtual method resolution (reduces candidate names from 1000+ to ~12)- Falls back to runtime reflection when APT-generated data is unavailable
- Per-class
get_virtual_funcupcall stubs — lazy, only created for methods the user actually overrides - APT-generated per-parent-class hash resolution — eliminates false matches across unrelated classes sharing method names
MethodHandlepre-cached dispatch with reflection fallback- Hash collision resolution by
StringNamepointer comparison
notification_func— forwards Godot notifications toonNotification(int)on the Java instanceto_string_func— bridges JavatoString()to Godot's string representationreference_func/unreference_func— atomic reference counting forRefCounted-derived classesvalidate_property_func— property validation pass-through for editor integration
- Zero-copy typed pointer dispatch — avoids
Variantboxing overhead for method calls - RefCounted-aware — uses
ref_get_object/ref_set_objectforRefPtrparameters - APT-generated
MethodHandledispatch for registered@GodotMethodmethods
@Exportannotation withhintandhintStringfor Godot editor integrationget_property_list_func— exposes@Exportfields to the Godot Inspectorproperty_can_revert_func/property_get_revert_func— default value support for revert behavior@Signalannotation for signal declaration and emission from Java
Some key technical choices in this project:
-
GDExtension (Godot 4 official extension mechanism)
- No reliance on legacy GDNative/JNI plugin approaches
- Aligned with Godot’s loading and lifecycle model
- Distributed as a shared library (
.dylib / .so / .dll)
-
Java 25 Panama FFI
- Uses the standard FFI API in the JDK (
java.lang.foreign) - Function signatures and memory layouts are modeled via
FunctionDescriptor/MemoryLayout - Easier to navigate and refactor in IDEs
- Uses the standard FFI API in the JDK (
-
Annotation-based registration model
- Generates the registration data Godot needs from annotations and reflection
- Avoids writing repetitive registration code on the C/C++ side
- Feels more like writing a normal Java application
There are several ways to bring other languages into Godot. Here is how godot-java compares to the main alternatives:
| Integration | FFI | Virtual methods | ptrcall | Barrier to entry | Maturity | |
|---|---|---|---|---|---|---|
| godot-java | GDExtension | Panama FFI (Java 25) | All 1144 | Supported | Low (no engine recompile) | Alpha |
| godot-rust/gdext | GDExtension | Rust FFI | All supported | Supported | Low (no engine recompile) | Stable |
| graphics.gd (Go) | GDExtension | CGO | Supported | — | Low (no engine recompile) | Community |
| godot-kotlin-jvm | Engine module | JNI | All supported | Supported | High (requires recompiling Godot) | Stable |
| C# (official) | Engine module | N/A | All supported | Supported | Medium (Mono embedded) | Official |
The fundamental difference is how a language integrates with Godot:
-
GDExtension is Godot 4's official plugin API. Languages built on it compile to a shared library (
.so/.dylib/.dll) that Godot loads at runtime. No engine recompilation is needed — users download a standard Godot binary and load the extension. This is the path taken by godot-java, gdext, and graphics.gd. -
Engine module compiles the language directly into the Godot C++ process. This gives full access to everything the engine offers (all virtual methods,
Input.*, etc.) but requires recompiling the entire Godot engine from source. This is the path taken by godot-kotlin-jvm (due to JVM embedding requirements) and C# (Godot's built-in option).
godot-java follows the GDExtension path. It supports all 1144 virtual methods across all Godot classes, auto-scanned from extension_api.json. The dispatch architecture is aligned with gdext (Rust bindings): upcall stubs are created lazily at class registration time, only for methods the user actually overrides. Unimplemented methods return NULL so Godot uses its default C++ implementation.
If you are coming from gdext: godot-java aims for a similar architecture, with Java instead of Rust and Panama FFI instead of native Rust FFI.
There are two documentation tracks: English and Chinese.
- Index:
docs/README.md- Explains the documentation structure
- Helps you find the right language / role-specific docs
Under docs/en/:
docs/en/user/getting-started.md— Requirements, build, loading the extension in Godotdocs/en/user/api.md— API overview and common typesdocs/en/user/guide.md— Usage guide and best practicesdocs/en/user/troubleshooting.md— Common issues and debugging tipsdocs/en/dev/architecture.md— Internal architecture (GDExtension + FFI)docs/en/dev/building.md— Build, packaging, and upgrading Godot versiondocs/en/dev/contributing.md— How to contributedocs/en/dev/debugging.md— Debugging Godot/Java integration
godot-java/
├── pom.xml # Root Maven project (aggregator)
├── godot-api/ # Godot API JSON files (input to code generator)
│ ├── extension_api.json # Godot class/method/property definitions
│ ├── gdextension_interface.json # GDExtension C interface definitions
│ └── gdextension_interface.h # GDExtension C header (reference)
├── godot-java-core/ # Core runtime and Godot Java bindings
│ ├── native/src/godot_java.cpp # C++ entry point (GDExtension initialization)
│ ├── src/main/java/org/godot/
│ │ ├── annotation/ # @GodotClass, @GodotMethod, @Export, @Signal
│ │ ├── bootstrap/ # JVM startup & GDExtension entry
│ │ ├── bridge/ # Panama FFI bridge (VirtualDispatch, InstanceCallbacks)
│ │ ├── core/ # Variant, StringName, GodotString, Callable…
│ │ ├── collection/ # GodotArray, GodotDictionary
│ │ ├── math/ # Vector2/Vector3, Transform2D/3D…
│ │ ├── node/ # 1016 generated node wrappers (Node, Node2D, Control…)
│ │ ├── internal/api/ # Auto-generated: ApiIndex, ApiSignatures, VariantType, VirtualMethods…
│ │ └── registration/ # Annotation scanning & class registration
│ └── src/test/java/ # Unit tests
├── godot-java-code-generator/ # Code generator (from Godot API JSON)
│ └── src/main/java/com/godot/codegen/
│ ├── Main.java # Entry point
│ ├── ApiIndexGenerator.java # 176 API function indices
│ ├── ApiSignaturesGenerator.java # Panama FunctionDescriptors
│ ├── VariantTypeGenerator.java # Variant type enum
│ ├── VirtualMethodGenerator.java # Virtual method metadata
│ ├── ClassGenerator.java # 1016 node wrapper classes
│ └── StructLayoutComputer.java # C struct offset calculator
├── godot-java-processor/ # APT annotation processor
│ └── src/main/java/org/godot/processor/
│ └── GodotClassProcessor.java # Generates TypedDispatch/VirtualDispatch at compile time
├── godot-java-examples/ # Example projects (10 examples)
│ ├── src/main/java/examples/ # Java source (helloworld, pong, snake…)
│ └── examples/01-*/~10-*/ # Godot projects with .tscn, .gd, native/
├── upgrade-godot-api.sh # One-command Godot version upgrade
└── docs/ # Documentation (EN + ZH)
├── en/user/ | en/dev/
└── zh/user/ | zh/dev/
When Godot releases a new version, godot-java can be upgraded in one step:
./upgrade-godot-api.sh 4.7This script:
- Downloads the new
extension_api.jsonandgdextension_interface.jsonfrom godot-cpp - Re-runs the code generator, which auto-updates:
- ApiIndex.java — 176 API function indices
- ApiSignatures.java — Panama FunctionDescriptor for each function
- VariantType.java — Variant type enum
- StructOffsets.java — C struct field offsets
- VirtualMethods.java — virtual method metadata (1144 methods, name→hash lookup)
- ObjectMethodHashes.java — method bind hashes for Object
- 1016 node wrapper classes — engine type API changes
Then verify:
./mvnw clean install -DskipTestsTo get a demo running:
-
Make sure you have:
- JDK 25+
- Maven 4.0.x
- Godot
-
Read:
-
Then:
- Build
godot-java-coreandgodot-java-code-generator - Load the built GDExtension into a new Godot project
- Create a simple
@GodotClass-annotated Java script and experiment
- Build
Contributions are very welcome:
- Bug reports, design discussions, and UX feedback
- Documentation improvements
- Platform / Godot version compatibility testing
- Expanding API coverage and tests
See: docs/en/dev/contribution.md
- The Godot Engine team and community for an open, powerful engine and GDExtension API
- The OpenJDK Panama team for bringing modern FFI to Java
- Everyone who has tried to use Java in game development – this project is also for you.