Crates.io | java-pack |
lib.rs | java-pack |
version | 0.1.0-alpha.4 |
source | src |
created_at | 2024-07-21 22:56:47.851427 |
updated_at | 2024-08-15 22:02:51.803686 |
description | ☕ + 🦀 = ❤️🔥 Java JNI Bindings Generator |
homepage | |
repository | https://github.com/PawelJastrzebski/java-bindgen |
max_upload_size | |
id | 1310622 |
size | 79,837 |
Welcome to java-bindgen, an easy-to-use Java JNI (Java Native Interface) bindings generator and CLI tool for building Java JARs. This tool simplifies the process of integrating Rust and Java, enabling you to leverage Rust's performance and safety in your Java applications.
Develop a robust and safe framework that facilitates seamless and secure integration between Java and Rust using JNI, minimizing the complexity and risks associated with native code interoperability.
JResult<T, JException>
with propagation to the Java layer.String
, byte[]
, int
, long
, float
, boolean
, etc.#[derive(JavaClass)]
for seamless integration.#[derive(JLogger)]
for better debugging and logging support.stack trace
attached to Java Exceptions for improved error diagnostics.java.util.List<E>
with Rust JList<E>
.Option<T>
.Install Rust and Cargo:
Install java-pack
CLI 🛠️
cargo install java-pack --version <version>
Example:
cargo install java-pack --version 0.1.0-alpha.4
Add java-bindgen
dependency
cargo add java-bindgen
Add Cargo.toml
configuration:
[package.metadata.java-bindgen]
package = "your.java.package"
Set crate-type
:
[lib]
crate-type = ["cdylib"]
To confirm your setup, run the following command:
java-pack info
☢️ The following examples do not compile due to missing configurations in the Cargo.toml file. ☢️
lib.rs
use java_bindgen::prelude::*;
#[derive(Default, JavaClass)]
struct User {
name: String,
}
#[java_bindgen]
fn getUser() -> JResult<User> {
Ok(User {
name: "Tom".to_string(),
})
}
Building jar 🫙
java-pack build
Produces the following Java interface and User class:
public static native User getUser();
@ToString
@Getter
@Setter
@AllArgsConstructor
public class User {
String name;
}
Create Java test project:
java-pack new-test
Add Test:
@Test
public void should_get_user() {
UserClass user = TestMacro.getUser();
assertEquals("Tom", user.getName());
}
Run tests:
java-pack test
Target | |||||
---|---|---|---|---|---|
Windows | Linux | MacOS | |||
JVM | Windows | ✅ | ✅* | ❔ | |
Linux | WSL 🐧 | ✅ | ❔ | ||
MacOS | 🚫 | 🚫 | ❔ |
Legend
✅ Supported
🚫 Unsupported
❔ No Data
Install linker: x86_64-w64-mingw32-gcc
sudo apt install mingw-w64`
Build .dll
and .so
cargo build --target=x86_64-pc-windows-gnu --target=x86_64-unknown-linux-gnu
Although this crate forbids unsafe
code, the underlying JNI
(Java Native Interface) itself is not inherently safe. Therefore, thorough testing is required to ensure that your software is safe to run.
🚨 Any Rust panic that is not handled on the Rust side will cause the JVM to crash. 🚨
java-bindgen
- lib
java-pack
- cli tool
java-bindgen-macro
- macro system
java-bindgen-core
- shared lib
Project is in early state of development. Each release is prior tested but api changes will most likely to happen in the future as the project progress.
To be determined. If you like the project, please consider giving it a ⭐, filing an issue ❗, or submitting a pull request (PR) ✅. Your feedback and contributions are highly appreciated!
This crate was developed and tested on Linux so more tests are needed to ensure that it works on all platforms. Multiplatform jar support allso needs more testing.
lib.rs
use java_bindgen::prelude::*;
#[derive(JLogger)]
struct Log();
#[java_bindgen]
fn test_logger<'a>(env: &mut JNIEnv<'a>, name: String) -> JResult<()> {
let logger = Log::init(env);
let msg = format!("Hello {name}, Welcome to Rust!");
logger.info(msg, env);
Ok(())
}
output
[main] INFO com.test.macro.TestMacro - Hello Java Bindgen, Welcome to Rust!
Rust
#[java_bindgen]
fn raw_object_to_string<'a>(env: &mut JNIEnv<'a>, input: JObject<'a>) -> JResult<String> {
let input_str: String = input.into_rust(env)?;
Ok(input_str)
}
Java signature:
String raw_object_to_string(Object input)
When Java pass non String Object
java.lang.UnsupportedOperationException:
Rust Error: JNI call failed
Cause: Cast failed [JObject -> String]
Rust Backtrace:
0: <core::result::Result<T,E> as java_bindgen::exception::JavaCatch<T>>::j_catch_cause
at /Projects/java_bindgen/src/exception.rs:145:17
1: <jni::wrapper::objects::jobject::JObject as java_bindgen::interop::java_to_rust::IntoRustType<alloc::string::String>>::into_rust
at /Projects/java_bindgen/src/interop.rs:87:13
2: test_macro::raw_input_type::raw_input_type_2
at /Projects/java_bindgen/examples/test-macro/src/lib.rs:390:33
3: Java_com_test_macro_TestMacro_raw_1input_1type_12
at /Projects/java_bindgen/examples/test-macro/src/lib.rs:388:5
4: <unknown>
Rust
#[derive(Default, JavaClass)]
struct Element {
parent: Node,
children: JList<Node>,
}
#[derive(Default, JavaClass)]
struct Node {
node_id: i32,
}
#[java_bindgen]
fn add_new_node(node: Node, element: Element) -> JResult<Element> {
let mut update = element;
update.children.add(node);
Ok(update)
}
Java
Node parent = new Node(1);
Node child = new Node(2);
Element element = Element.builder().children(new LinkedList<>()).parent(parent).build();
Element updated = Lib.add_new_node(child, element);
System.out.println("Updated: " + updated);
output
Updated: Element(parent=Node(node_id=1), children=[Node(node_id=2)])
For full examples visit: github.com/java-bindgen/examples
Thank you to the jni team!
This project strongly relies on the jni crate, and without your hard work, it would not have been possible.