4个版本
新 0.1.0-alpha.4 | 2024年8月15日 |
---|---|
0.1.0-alpha.3 | 2024年8月5日 |
0.1.0-alpha.2 | 2024年8月1日 |
0.1.0-alpha.1 | 2024年7月21日 |
#1157 in 过程宏
454 每月下载
在 java-bindgen 中使用
75KB
1.5K SLoC
☕ + 🦀 = ❤️🔥
Java JNI 绑定生成器
简介 👋
欢迎使用java-bindgen,这是一个易于使用的Java JNI(Java本地接口)绑定生成器和CLI工具,用于构建Java JAR。此工具简化了Rust和Java的集成过程,使您能够利用Rust的性能和安全特性来提高Java应用程序。
目标 🚀
开发一个健壮且安全的框架,使用JNI(Java本地接口)在Java和Rust之间实现无缝且安全集成,最大程度地减少与本地代码互操作相关的复杂性和风险。
特性 🎖️
- 使用
JResult<T, JException>
进行便捷的错误处理,并将其传播到Java层。 - 自动转换Java原始类型,如
String
、byte[]
、int
、long
、float
、boolean
等。 - 使用
#[derive(JavaClass)]
进行自定义类型,实现无缝集成。 - 集成Logger
#[derive(JLogger)]
以提供更好的调试和日志支持。 - 将Rust错误
stack trace
附加到Java异常,以改进错误诊断。 - 支持使用 Rust
java.util.List<E>
与 JavaJList<E>
。 - 使用
Option<T>
在 Rust 中支持 Java 可空类型。
先决条件
安装 Rust 和 Cargo
Rust 项目设置 🦀
安装 java-pack
CLI 🛠️
cargo install java-pack --version <version>
示例
cargo install java-pack --version 0.1.0-alpha.4
添加 java-bindgen
依赖项
cargo add java-bindgen
添加 Cargo.toml
配置
[package.metadata.java-bindgen]
package = "your.java.package"
设置 crate-type
[lib]
crate-type = ["cdylib"]
验证您的配置 🔦
为了确认您的设置,运行以下命令
java-pack info
示例
☢️ 以下示例由于 Cargo.toml 文件中缺少配置而无法编译。 ☢️
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(),
})
}
构建 jar 🫙
java-pack build
生成以下 Java 接口和 User 类
public static native User getUser();
@ToString
@Getter
@Setter
@AllArgsConstructor
public class User {
String name;
}
测试 💯
创建 Java 测试项目
java-pack new-test
添加测试
@Test
public void should_get_user() {
UserClass user = TestMacro.getUser();
assertEquals("Tom", user.getName());
}
运行测试
java-pack test
跨平台构建
目标 | 构建平台 | ||||
---|---|---|---|---|---|
Windows | Linux | MacOS | |||
JVM | Windows | ✅ | ✅* | ❔ | |
Linux | WSL 🐧 | ✅ | ❔ | ||
MacOS | 🚫 | 🚫 | ❔ |
图例
- ✅ 支持的
- 🚫 不支持的
- ❔ 没有数据
*Linux -> Windows
安装链接器: x86_64-w64-mingw32-gcc
sudo apt install mingw-w64`
构建 .dll
和 .so
cargo build --target=x86_64-pc-windows-gnu --target=x86_64-unknown-linux-gnu
安全性 🛡️
虽然此 crate 禁止 unsafe
代码,但底层的 JNI
(Java 本地接口)本身 不是固有的安全。因此,需要进行彻底的 测试 以确保您的软件安全运行。
🚨 任何未在 Rust 端处理的 Rust 程序崩溃将导致 JVM 崩溃。 🚨
项目 📦
项目结构 📌
java-bindgen
- libjava-pack
- CLI 工具java-bindgen-macro
- 宏系统java-bindgen-core
- 共享库
项目状态 🚧
项目处于早期开发阶段。每个版本都经过预先测试,但未来的 API 变化很可能随着项目进展而出现。
路线图 📆
待定。如果您喜欢这个项目,请考虑给它一个 ⭐,提交一个 issue ❗,或提交一个 pull request (PR) ✅。您的反馈和贡献将受到高度重视!
Alpha ❗
此 crate 在 Linux 上开发和测试,因此需要更多测试以确保它在所有平台上都能工作。多平台 jar 支持也需要更多测试。
更多示例 🤖
记录器
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(())
}
输出
[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 签名
String raw_object_to_string(Object input)
当 Java 传递非 String 对象时
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);
输出
Updated: Element(parent=Node(node_id=1), children=[Node(node_id=2)])
完整示例 🧭
有关完整示例,请访问: github.com/java-bindgen/examples
致谢 💌
感谢 jni 团队!
此项目强烈依赖于 jni crate,没有您的辛勤工作,这是不可能实现的。
依赖项
~1.5–2.7MB
~50K SLoC