0

I am trying to call the JNI function CallStaticVoidMethod from rust. The jni-sys wrapper declares it as

pub CallStaticVoidMethod:
    Option<unsafe extern "C" fn(env: *mut JNIEnv, cls: jclass, methodID: jmethodID, ...)>,

I would like to wrap this call in something safer, so I have created this method on my wrapper object:

pub fn call_static_void_method(&mut self, cls: jclass, method: jmethod, args: & Vec<jobject>)
{
    let csvm;
    unsafe {
        csvm = (**self.env_ptr).CallStaticVoidMethod.expect("no implementation of CallStaticVoidMethod");
    }
    unsafe {
        return csvm(self.env_ptr, cls, method, /*what here?*/);
    }
}

How can I convert args:Vec<jobject> so that I can provide the final arguments to the CallStaticVoidMethod JNI function?

Mutant Bob
  • 3,121
  • 2
  • 27
  • 52

1 Answers1

1

You can call variadic C functions from rust in the normal way, however calling them with an argument list that is only known at runtime is another matter. From what I understand, it is not even really possible in C (at least not in a standards compliant manner).

Luckily, though, it looks as though you don't need to do that. The JNI provides an alternative method, CallStaticVoidMethodA, which is defined as:

NativeType CallStaticVoidMethodA(JNIEnv *env, jclass clazz, jmethodID methodID, jvalue *args);

where args points to an array containing the arguments, in the form of jvalue.

You are receiving a Vec<jobject>; a jvalue is a union of various kinds of value, so you will need to convert your Vec<jobject> into an array of jvalues. Alternatively it would be more flexible if your function could accept Vec<jvalue> as you would be able to call methods that accept various argument types - in that case you could just pass args.as_ptr() like so:

pub fn call_static_void_method(&mut self, cls: jclass, method: jmethod, args: & Vec<jvalue>)
{
    let csvm;
    unsafe {
        csvm = (**self.env_ptr).CallStaticVoidMethodA.expect("no implementation of CallStaticVoidMethodA");
    }
    unsafe {
        return csvm(self.env_ptr, cls, method, args.as_ptr());
    }
}

There are variations on this theme for all of the JNI functions for calling methods.

See also: JNI Documentation

harmic
  • 28,606
  • 5
  • 67
  • 91
  • maybe, https://doc.rust-lang.org/nightly/std/ffi/struct.VaList.html#method.as_va_list, but this is very unconventional to create a va_list at the hand in C (in fact I don't think it's possible). – Stargateur Jun 21 '19 at 01:23
  • @Stargateur I hadn't noticed that - but since JNI provides an interface that takes a simple array, I would still use that in preference, rather than use an experimental nightly feature. – harmic Jun 21 '19 at 05:12