Rust JNI工具库jni-utils的使用:简化Java原生接口交互与跨平台开发
Rust JNI工具库jni-utils的使用:简化Java原生接口交互与跨平台开发
简介
jni-utils是一个建立在jni
crate之上的Rust库,它提供了更高级的概念来简化JNI交互。相比jni
crate实现的JNI底层绑定,jni-utils
更专注于常用的高级构造。
主要特性
- 使用
JFuture
和JStream
类型实现与Java代码的异步调用 - 常见Rust类型与其对应Java类型之间的转换
- 使用
try_block
函数模拟try
/catch
块
设计原则
jni-utils的核心设计原则是尽量减少Rust和Java代码之间的切换,同时使从Rust调用Java代码比从Java调用Rust代码更容易。调用Rust需要创建一个带有native
方法的类并从Rust导出,而调用Java只需要使用JNIEnv::call_method()
。
使用方法
简单构建方式
$ cargo build --features=build-java-support
Java支持库JAR将放置在target/<config>/java/libs
目录中。
高级构建方式
$ cargo build
$ cd java
$ ./gradlew build
添加依赖
在build.gradle
中添加:
dependencies {
implementation 'io.github.gedgygedgy.rust:jni-utils:0.1.0'
}
完整示例
以下是一个使用jni-utils的完整示例:
use jni::JNIEnv;
use jni::objects::{JObject, JValue};
use jni_utils::init;
fn main() {
// 初始化jni-utils
init().unwrap();
// 创建一个JVM实例
let jvm = jni::JavaVM::new(jni::InitArgs::default()).unwrap();
let env = jvm.attach_current_thread().unwrap();
// 示例1: 调用Java方法
let result = call_java_method(&env).unwrap();
println!("Java方法返回结果: {}", result);
// 示例2: 使用try_block处理异常
match try_block_example(&env) {
Ok(value) => println!("成功获取值: {}", value),
Err(e) => println!("捕获到异常: {:?}", e),
}
}
// 示例1: 调用Java方法
fn call_java_method(env: &JNIEnv) -> jni::errors::Result<i32> {
// 获取System类
let system_class = env.find_class("java/lang/System")?;
// 调用currentTimeMillis方法
let time = env.call_static_method(
system_class,
"currentTimeMillis",
"()J",
&[],
)?.j()?;
Ok(time as i32)
}
// 示例2: 使用try_block处理异常
fn try_block_example(env: &JNIEnv) -> jni::errors::Result<i32> {
// 使用try_block捕获异常
jni_utils::try_block(env, || {
// 尝试执行可能抛出异常的代码
let integer_class = env.find_class("java/lang/Integer")?;
let number = env.new_object(
integer_class,
"(I)V",
&[JValue::Int(42)],
)?;
// 调用parseInt方法,传入非数字字符串会抛出异常
let parsed = env.call_static_method(
"java/lang/Integer",
"parseInt",
"(Ljava/lang/String;)I",
&[JValue::Object(&JObject::from("not_a_number"))],
)?.i()?;
Ok(parsed)
})
}
注意事项
- 某些jni-utils功能需要配套的Java支持库,因此在使用jni-utils前应调用
jni_utils::init()
- 与Tokio异步运行时配合使用时可能需要额外的类缓存处理
扩展完整示例
以下是一个更完整的jni-utils使用示例,展示了异步调用和类型转换功能:
use jni::{JNIEnv, JavaVM};
use jni::objects::{JObject, JString, JValue};
use jni_utils::{init, JFuture};
use std::future::Future;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 初始化jni-utils
init().unwrap();
// 创建JVM实例
let jvm = JavaVM::new(jni::InitArgs::default())?;
let env = jvm.attach_current_thread()?;
// 示例3: 异步调用Java方法
let future = call_async_java_method(&env)?;
let result = future.await?;
println!("异步调用结果: {}", result);
// 示例4: 类型转换
let converted = convert_types(&env)?;
println!("转换后的值: {}", converted);
Ok(())
}
// 示例3: 异步调用Java方法
fn call_async_java_method(env: &JNIEnv) -> jni::errors::Result<JFuture<i32>> {
// 获取CompletableFuture类
let future_class = env.find_class("java/util/concurrent/CompletableFuture")?;
// 创建CompletableFuture实例
let future = env.new_object(future_class, "()V", &[])?;
// 调用complete方法
env.call_method(
future,
"complete",
"(I)Z",
&[JValue::Int(42)],
)?;
// 将Java Future转换为Rust的JFuture
JFuture::from_java(env, future)
}
// 示例4: 类型转换
fn convert_types(env: &JNIEnv) -> jni::errors::Result<String> {
// 创建一个Java字符串
let java_string = JString::from(env.new_string("Hello from Rust")?);
// 转换为Rust字符串
let rust_string: String = env.get_string(&java_string)?.into();
Ok(rust_string)
}
1 回复