java - 将未知的 Java 类型转换为 Rust 类型

标签 java rust java-native-interface

我正在尝试将 Java 中的 HashMap 转换为 Rust 并将其转换为内部对象,匹配数据类型等等。 java中的HashMap是HashMap<String, Object> Object可以是任何数据类型,包括另一个 HashMap<String, Object> .
我很难确定 JObject 是什么类型的对象是,我被阻止如何转换 JObject类似于 JString .
如您所见,我几乎没有使用它,但作为第一遍,我只想返回 String 的字符串值, Integer , 或 Date (其中 Date 将是 Date.getTime() 的字符串值)。

static DATE_CLASS: &str = "java/util/Date";
static INTEGER_CLASS: &str = "java/lang/Integer";
static STRING_CLASS: &str = "java/lang/String";

fn get_string_value(env: &JNIEnv, obj: JObject) -> String {
    let ret = String::new();

    if env.is_instance_of(obj, STRING_CLASS).unwrap() {
        let ret2 = env.call_method(obj, "toString", "()Ljava/lang/String;", &[]).unwrap();
        // Got a JValue- now what?
    }

    if env.is_instance_of(obj, INTEGER_CLASS).unwrap() {
        let ret2 = env.call_method(obj, "toString", "()Ljava/lang/String;", &[]).unwrap();
        // Got a JValue- now what?
    }

    if env.is_instance_of(obj, INTEGER_CLASS).unwrap() {
        let ret2 = env.call_method(obj, "getTime", "()Ljava/lang/String;", &[]).unwrap();
        // Got a JValue- now what?
    }

    ret
}
我认为我应该这样做(但如果不是,请纠正我),是检查 JObject通过它们的完全限定路径是这些类中的任何一个的实例。一旦我知道它们是什么类型,我就可以使用 env.call_method 调用它们的方法。 .结果是 JValue ,它可以返回一些原始类型。
enter image description here
我假设我应该使用这些,除非我期望返回另一个对象,在这种情况下我会使用 -
let message_ref = env.auto_local(ret2).as_obj();
然后,如果需要,我可以调用另一种方法。但据我所知,如果我愿意,我无法将其转换为 JString。但是,到目前为止,这也是我知道如何从 JString 中取出使用rust 字符串的唯一方法,方法是:
let s: String = env.get_string(a_j_string).expect("Couldn't get java string").into();
我这样做对吗?
如何将 JValue 转换为字符串?
我应该使用 auto_local 是否正确?转换 JValueJObject ,这将允许我再次调用它的方法?
如果我应该使用原始类型 jchar得到 toString 的值- 如何将其转换为 &strString ?
编辑:
在@Chris Jester-Young 的帮助下,我能够同时获得 jobj_to_stringjobj_to_int功能工作。
static INTEGER_CLASS: &str = "java/lang/Integer";
static STRING_CLASS: &str = "java/lang/String";

fn get_liquid_value(env: &JNIEnv, obj: JObject) -> LiquidValue {
    let mut value = LiquidValue::Nil;

    if env.is_instance_of(obj, STRING_CLASS).unwrap() {
        match jobj_to_string(env, obj) {
            Some(str) => {
                value = LiquidValue::Scalar(LiquidScalar::from(str));
            },
            None => {}
        }
    }

    if env.is_instance_of(obj, INTEGER_CLASS).unwrap() {
        match jobj_to_i32(env, obj) {
            Some(int) => {
                value = LiquidValue::Scalar(LiquidScalar::from(int));
            },
            None => {}
        }
    }

    value
}

fn jobj_to_string(env: &JNIEnv, obj: JObject) -> Option<String> {
    let mut result = Option::None;

    match env.call_method(obj, "toString", "()Ljava/lang/String;", &[]) {
        Result::Ok(jvalue) => {
            match jvalue.l() {
                Result::Ok(jobject) => {
                    let string = String::from(env.get_string(jobject.into()).unwrap().to_str().unwrap());
                    result = Option::Some(string);
                },
                _ => {}
            }
        },
        _ => {}
    };

    result
}

fn jobj_to_i32(env: &JNIEnv, obj: JObject) -> Option<i32> {
    let mut result = Option::None;

    match env.call_method(obj, "intValue", "()I", &[]) {
        Ok(jvalue) => {
            match jvalue.i() {
                Ok(int) => {
                    result = Option::Some(int.to_owned());
                },
                _ => {}
            }
        },
        _ => {}
    }

    result
}

最佳答案

jni crate , JObjectJString只是 JNI 的 jobject 的包装器和 jstring .你可以“投”一个JObject变成 JString使用 From特征。例如,JString::from(my_jobject)my_jobject.into() .你必须做一个JNIEnv::is_instance_of但是,如果您完全不确定该对象是否实际上是一个字符串,请先检查一下。
关于 JValue 的问题,toString 的结果是一个字符串,在 JVM 世界中,它是一种对象类型,而不是原始类型。所以你可以使用 JValue::l访问器(据我所知,您不需要使用 auto_local)。由于我们知道结果是一个字符串,您可以将结果转换为 JString直接(如上所述),然后调用JNIEnv::get_string获取 JavaStr对象,您可以使用 From 将其转换为 Rust 字符串特征。
将它们放在一起,我们得到以下结果(未经测试,但至少可以为我编译):

fn get_string_value(env: &JNIEnv, obj: JObject<'_>) -> Result<String> {
    let result = env.call_method(obj, "toString", "()Ljava/lang/String;", &[])?.l()?;
    Ok(env.get_string(result.into())?.into())
}

关于java - 将未知的 Java 类型转换为 Rust 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63946475/

相关文章:

java - 如何将 Java 对象类型(如 Long 和 Integer)转换为原始类型(如 long 和 int)

java - 将 C++ 原始类型 vector 转换为 Java 原始类型数组

rust - 由于在 "thread '上出现了 'called ` main错误,导致无法创建通用JNIEnv结果:: unwrap()` on an ` Err`值

Java Web 服务和 SOAP - 更改元素名称

java - IntelliJ插件: how to use a custom FrameTitleBuilder?

Rust:无法在线程之间安全地共享 impl 特征

rust - 模板中关联类型的特征

java - Spring Java 电子邮件异常

java - 锁定具有非透明 Activity 的 Android API 27 时的屏幕方向

parsing - 使用 `nom` 处理自定义枚举类型是否有意义?