有没有一种简便的方法从 Rust 调用 Java 函数?

huangapple go评论81阅读模式
英文:

Is there a streamlined way to invoke java functions from rust?

问题

对于通过 `jni` crate  Rust 调用 Java 的理解涉及到一些看起来有点样板的代码,如下所示:

```rust
je.call_method(self.rimuru, "shell2Pixels", "(II[B)V", &[
    JValue::from(width),
    JValue::from(height),
    JValue::from(rgbs.as_obj()),
])?;

我想象中可以通过宏来改进这个过程。也许可以这样做:

java_call_method!(self.rimuru, "shell2Pixels", (), width, height, rgbs)?;

这个宏将负责根据各个参数的类型构建签名字符串 (II[B)V

类似这样的东西是否已经存在而我尚未发现?我不确定是否可以使用普通宏来实现,而不是过程宏。


<details>
<summary>英文:</summary>

My understanding of invoking java from rust via the `jni` crate involves a bit of boilerplate that looks like

je.call_method(self.rimuru, "shell2Pixels", "(II[B)V", &[
JValue::from(width),
JValue::from(height),
JValue::from(rgbs.as_obj()),
])?;


I am imagining that this could be improved using macros.  Perhaps something like

```java_call_method!(self.rimuru, &quot;shell2Pixels&quot;, (), width, height, rgbs)?; ```

The macro would be responsible for building the signature string `(II[B)V` from the types of the various arguments.

Does something like this already exist and I have not discovered it?  I am not sure if it can be implemented using regular macros instead of procedural macros.

</details>


# 答案1
**得分**: 1

经过一番混乱的探索,我创建了 https://github.com/mutantbob/rust_jni_boilerplate,其中包含一小组生成样板代码的过程宏。

(截至2020年8月)它的使用方式如下:

```rust
struct Widget<'a> {
    jni_env: &'a AttachGuard<'a>,
    java_this: AutoLocal<'a, 'a>,
}

impl<'a> JavaConstructible<'a> for Widget<'a> {
    fn wrap_jobject(jni_env: &'a AttachGuard<'a>, java_this: AutoLocal<'a, 'a>) -> Widget<'a> {
        Widget {
            jni_env,
            java_this,
        }
    }
}

impl<'a> Widget<'a> {

    // 定义一个名为 new 的 Rust 函数
    jni_constructor! { com.purplefrog.rust_callables.Widget () }
    jni_constructor! { new_one=com.purplefrog.rust_callables.Widget (&str) }

    jni_instance_method! { count () -> i32 }
    jni_instance_method! { sumLen () -> i32 }

    jni_instance_method! { add(&str) }

    jni_instance_method! { echo_str=echo(&str) -> String }
    jni_instance_method! { echo_char=echo(char) -> char }
    jni_instance_method! { echo_byte=echo(i8) -> i8 }
    jni_instance_method! { echo_short=echo(i16) -> i16 }
    jni_instance_method! { echo_int=echo(i32) -> i32 }
    jni_instance_method! { echo_long=echo(i64) -> i64 }

    jni_instance_method! { to_strings = toStrings() -> Vec<String> }
}

它的类型支持可能存在明显的漏洞。它的架构在开发过程中发生了重大变化。我甚至不确定自己是否以合乎惯例的方式使用了过程宏 API。它基于的 jni crate 很难被认为是安全的(在从 Rust 调用 Java 时很容易泄漏内存)。但是我已经成功让它在有限的用例中工作。

我希望它能够激发其他人的灵感,做得更好。也许它可以作为编写过程宏的示例,直到有人撰写了一篇适当的文章(通过谷歌搜索,我并没有找到任何关于此方面的好文章)。

英文:

After a great deal of wallowing in confusion I have created https://github.com/mutantbob/rust_jni_boilerplate which has a small set of procedural macros that generate boilerplate.

(as of 2020-Aug) It is used like this:

struct Widget&lt;&#39;a&gt; {
    jni_env: &amp;&#39;a AttachGuard&lt;&#39;a&gt;,
    java_this: AutoLocal&lt;&#39;a,&#39;a&gt;,
}

impl&lt;&#39;a&gt; JavaConstructible&lt;&#39;a&gt; for Widget&lt;&#39;a&gt;
{
    fn wrap_jobject(jni_env:&amp;&#39;a AttachGuard&lt;&#39;a&gt;, java_this: AutoLocal&lt;&#39;a,&#39;a&gt;) -&gt; Widget&lt;&#39;a&gt;
    {
        Widget {
            jni_env,
            java_this,
        }
    }
}

impl&lt;&#39;a&gt; Widget&lt;&#39;a&gt; {

    // define a rust function named new
    jni_constructor! { com.purplefrog.rust_callables.Widget () }
    jni_constructor! { new_one=com.purplefrog.rust_callables.Widget (&amp;str) }

    jni_instance_method! { count () -&gt; i32 }
    jni_instance_method! { sumLen () -&gt; i32 }

    jni_instance_method! { add(&amp;str) }

    jni_instance_method! { echo_str=echo(&amp;str)-&gt;String }
    jni_instance_method! { echo_char=echo(char)-&gt;char }
    jni_instance_method! { echo_byte=echo(i8)-&gt;i8 }
    jni_instance_method! { echo_short=echo(i16)-&gt;i16 }
    jni_instance_method! { echo_int=echo(i32)-&gt;i32 }
    jni_instance_method! { echo_long=echo(i64)-&gt;i64 }

    jni_instance_method! { to_strings = toStrings() -&gt;Vec&lt;String&gt; }
}

There are probably gaping holes in its type support. Its architecture has mutated drastically during development. I'm not even sure I'm using the procedural macro API idiomatically. The jni crate it is based on can hardly be considered safe (it is very easy to leak memory when you are calling java from rust). But I have managed to make it work for my limited use case.

I am hoping it serves as an inspiration for someone else to do better. Maybe it will be useful as an example of how to write procedural macros until someone writes a proper article (google search didn't exactly give me any good articles about it).

huangapple
  • 本文由 发表于 2020年7月25日 03:06:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/63080035.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定