1 use std::{
2     marker::PhantomData,
3     os::raw::{c_char, c_void},
4     ptr, slice, str,
5     str::FromStr,
6     sync::{Mutex, MutexGuard},
7 };
8 
9 use log::warn;
10 
11 use crate::{
12     descriptors::Desc,
13     errors::*,
14     objects::{
15         AutoArray, AutoLocal, AutoPrimitiveArray, GlobalRef, JByteBuffer, JClass, JFieldID, JList,
16         JMap, JMethodID, JObject, JStaticFieldID, JStaticMethodID, JString, JThrowable, JValue,
17         ReleaseMode, TypeArray,
18     },
19     signature::{JavaType, Primitive, TypeSignature},
20     strings::{JNIString, JavaStr},
21     sys::{
22         self, jarray, jboolean, jbooleanArray, jbyte, jbyteArray, jchar, jcharArray, jdouble,
23         jdoubleArray, jfloat, jfloatArray, jint, jintArray, jlong, jlongArray, jobjectArray,
24         jshort, jshortArray, jsize, jvalue, JNINativeMethod,
25     },
26     JNIVersion, JavaVM,
27 };
28 
29 /// FFI-compatible JNIEnv struct. You can safely use this as the JNIEnv argument
30 /// to exported methods that will be called by java. This is where most of the
31 /// magic happens. All methods on this object are wrappers around JNI functions,
32 /// so the documentation on their behavior is still pretty applicable.
33 ///
34 /// # Exception handling
35 ///
36 /// Since we're calling into the JVM with this, many methods also have the
37 /// potential to cause an exception to get thrown. If this is the case, an `Err`
38 /// result will be returned with the error kind `JavaException`. Note that this
39 /// will _not_ clear the exception - it's up to the caller to decide whether to
40 /// do so or to let it continue being thrown.
41 ///
42 /// ## `null` Java references
43 /// `null` Java references are handled by the following rules:
44 ///   - If a `null` Java reference is passed to a method that expects a non-`null`
45 ///   argument, an `Err` result with the kind `NullPtr` is returned.
46 ///   - If a JNI function returns `null` to indicate an error (e.g. `new_int_array`),
47 ///     it is converted to `Err`/`NullPtr` or, where possible, to a more applicable
48 ///     error type, such as `MethodNotFound`. If the JNI function also throws
49 ///     an exception, the `JavaException` error kind will be preferred.
50 ///   - If a JNI function may return `null` Java reference as one of possible reference
51 ///     values (e.g., `get_object_array_element` or `get_field_unchecked`),
52 ///     it is converted to `JObject::null()`.
53 ///
54 /// # Checked and unchecked methods
55 ///
56 /// Some of the methods come in two versions: checked (e.g. `call_method`) and
57 /// unchecked (e.g. `call_method_unchecked`). Under the hood, checked methods
58 /// perform some checks to ensure the validity of provided signatures, names
59 /// and arguments, and then call the corresponding unchecked method.
60 ///
61 /// Checked methods are more flexible as they allow passing class names
62 /// and method/field descriptors as strings and may perform lookups
63 /// of class objects and method/field ids for you, also performing
64 /// all the needed precondition checks. However, these lookup operations
65 /// are expensive, so if you need to call the same method (or access
66 /// the same field) multiple times, it is
67 /// [recommended](https://docs.oracle.com/en/java/javase/11/docs/specs/jni/design.html#accessing-fields-and-methods)
68 /// to cache the instance of the class and the method/field id, e.g.
69 ///   - in loops
70 ///   - when calling the same Java callback repeatedly.
71 ///
72 /// If you do not cache references to classes and method/field ids,
73 /// you will *not* benefit from the unchecked methods.
74 ///
75 /// Calling unchecked methods with invalid arguments and/or invalid class and
76 /// method descriptors may lead to segmentation fault.
77 #[derive(Clone, Copy)]
78 #[repr(transparent)]
79 pub struct JNIEnv<'a> {
80     internal: *mut sys::JNIEnv,
81     lifetime: PhantomData<&'a ()>,
82 }
83 
84 impl<'a> JNIEnv<'a> {
85     /// Create a JNIEnv from a raw pointer.
86     ///
87     /// # Safety
88     ///
89     /// Expects a valid pointer retrieved from the `GetEnv` JNI function. Only does a null check.
from_raw(ptr: *mut sys::JNIEnv) -> Result<Self>90     pub unsafe fn from_raw(ptr: *mut sys::JNIEnv) -> Result<Self> {
91         non_null!(ptr, "from_raw ptr argument");
92         Ok(JNIEnv {
93             internal: ptr,
94             lifetime: PhantomData,
95         })
96     }
97 
98     /// Get the java version that we're being executed from.
get_version(&self) -> Result<JNIVersion>99     pub fn get_version(&self) -> Result<JNIVersion> {
100         Ok(jni_unchecked!(self.internal, GetVersion).into())
101     }
102 
103     /// Load a class from a buffer of raw class data. The name of the class must match the name
104     /// encoded within the class file data.
define_class<S>(&self, name: S, loader: JObject<'a>, buf: &[u8]) -> Result<JClass<'a>> where S: Into<JNIString>,105     pub fn define_class<S>(&self, name: S, loader: JObject<'a>, buf: &[u8]) -> Result<JClass<'a>>
106     where
107         S: Into<JNIString>,
108     {
109         let name = name.into();
110         self.define_class_impl(name.as_ptr(), loader, buf)
111     }
112 
113     /// Load a class from a buffer of raw class data. The name of the class is inferred from the
114     /// buffer.
define_unnamed_class<S>(&self, loader: JObject<'a>, buf: &[u8]) -> Result<JClass<'a>> where S: Into<JNIString>,115     pub fn define_unnamed_class<S>(&self, loader: JObject<'a>, buf: &[u8]) -> Result<JClass<'a>>
116     where
117         S: Into<JNIString>,
118     {
119         self.define_class_impl(ptr::null(), loader, buf)
120     }
121 
define_class_impl( &self, name: *const c_char, loader: JObject<'a>, buf: &[u8], ) -> Result<JClass<'a>>122     fn define_class_impl(
123         &self,
124         name: *const c_char,
125         loader: JObject<'a>,
126         buf: &[u8],
127     ) -> Result<JClass<'a>> {
128         let class = jni_non_null_call!(
129             self.internal,
130             DefineClass,
131             name,
132             loader.into_inner(),
133             buf.as_ptr() as *const jbyte,
134             buf.len() as jsize
135         );
136         Ok(class)
137     }
138 
139     /// Look up a class by name.
140     ///
141     /// # Example
142     /// ```rust,ignore
143     /// let class: JClass<'a> = env.find_class("java/lang/String");
144     /// ```
find_class<S>(&self, name: S) -> Result<JClass<'a>> where S: Into<JNIString>,145     pub fn find_class<S>(&self, name: S) -> Result<JClass<'a>>
146     where
147         S: Into<JNIString>,
148     {
149         let name = name.into();
150         let class = jni_non_null_call!(self.internal, FindClass, name.as_ptr());
151         Ok(class)
152     }
153 
154     /// Returns the superclass for a particular class OR `JObject::null()` for `java.lang.Object` or
155     /// an interface. As with `find_class`, takes a descriptor.
get_superclass<'c, T>(&self, class: T) -> Result<JClass<'a>> where T: Desc<'a, JClass<'c>>,156     pub fn get_superclass<'c, T>(&self, class: T) -> Result<JClass<'a>>
157     where
158         T: Desc<'a, JClass<'c>>,
159     {
160         let class = class.lookup(self)?;
161         Ok(jni_non_void_call!(self.internal, GetSuperclass, class.into_inner()).into())
162     }
163 
164     /// Tests whether class1 is assignable from class2.
is_assignable_from<'t, 'u, T, U>(&self, class1: T, class2: U) -> Result<bool> where T: Desc<'a, JClass<'t>>, U: Desc<'a, JClass<'u>>,165     pub fn is_assignable_from<'t, 'u, T, U>(&self, class1: T, class2: U) -> Result<bool>
166     where
167         T: Desc<'a, JClass<'t>>,
168         U: Desc<'a, JClass<'u>>,
169     {
170         let class1 = class1.lookup(self)?;
171         let class2 = class2.lookup(self)?;
172         Ok(jni_unchecked!(
173             self.internal,
174             IsAssignableFrom,
175             class1.into_inner(),
176             class2.into_inner()
177         ) == sys::JNI_TRUE)
178     }
179 
180     /// Returns true if the object reference can be cast to the given type.
181     ///
182     /// _NB: Unlike the operator `instanceof`, function `IsInstanceOf` *returns `true`*
183     /// for all classes *if `object` is `null`.*_
184     ///
185     /// See [JNI documentation](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#IsInstanceOf)
186     /// for details.
is_instance_of<'c, O, T>(&self, object: O, class: T) -> Result<bool> where O: Into<JObject<'a>>, T: Desc<'a, JClass<'c>>,187     pub fn is_instance_of<'c, O, T>(&self, object: O, class: T) -> Result<bool>
188     where
189         O: Into<JObject<'a>>,
190         T: Desc<'a, JClass<'c>>,
191     {
192         let class = class.lookup(self)?;
193         Ok(jni_unchecked!(
194             self.internal,
195             IsInstanceOf,
196             object.into().into_inner(),
197             class.into_inner()
198         ) == sys::JNI_TRUE)
199     }
200 
201     /// Returns true if ref1 and ref2 refer to the same Java object, or are both `NULL`. Otherwise,
202     /// returns false.
is_same_object<'b, 'c, O, T>(&self, ref1: O, ref2: T) -> Result<bool> where O: Into<JObject<'b>>, T: Into<JObject<'c>>,203     pub fn is_same_object<'b, 'c, O, T>(&self, ref1: O, ref2: T) -> Result<bool>
204     where
205         O: Into<JObject<'b>>,
206         T: Into<JObject<'c>>,
207     {
208         Ok(jni_unchecked!(
209             self.internal,
210             IsSameObject,
211             ref1.into().into_inner(),
212             ref2.into().into_inner()
213         ) == sys::JNI_TRUE)
214     }
215 
216     /// Raise an exception from an existing object. This will continue being
217     /// thrown in java unless `exception_clear` is called.
218     ///
219     /// # Examples
220     /// ```rust,ignore
221     /// let _ = env.throw(("java/lang/Exception", "something bad happened"));
222     /// ```
223     ///
224     /// Defaulting to "java/lang/Exception":
225     ///
226     /// ```rust,ignore
227     /// let _ = env.throw("something bad happened");
228     /// ```
throw<'e, E>(&self, obj: E) -> Result<()> where E: Desc<'a, JThrowable<'e>>,229     pub fn throw<'e, E>(&self, obj: E) -> Result<()>
230     where
231         E: Desc<'a, JThrowable<'e>>,
232     {
233         let throwable = obj.lookup(self)?;
234         let res: i32 = jni_unchecked!(self.internal, Throw, throwable.into_inner());
235         if res == 0 {
236             Ok(())
237         } else {
238             Err(Error::ThrowFailed(res))
239         }
240     }
241 
242     /// Create and throw a new exception from a class descriptor and an error
243     /// message.
244     ///
245     /// # Example
246     /// ```rust,ignore
247     /// let _ = env.throw_new("java/lang/Exception", "something bad happened");
248     /// ```
throw_new<'c, S, T>(&self, class: T, msg: S) -> Result<()> where S: Into<JNIString>, T: Desc<'a, JClass<'c>>,249     pub fn throw_new<'c, S, T>(&self, class: T, msg: S) -> Result<()>
250     where
251         S: Into<JNIString>,
252         T: Desc<'a, JClass<'c>>,
253     {
254         let class = class.lookup(self)?;
255         let msg = msg.into();
256         let res: i32 = jni_unchecked!(self.internal, ThrowNew, class.into_inner(), msg.as_ptr());
257         if res == 0 {
258             Ok(())
259         } else {
260             Err(Error::ThrowFailed(res))
261         }
262     }
263 
264     /// Check whether or not an exception is currently in the process of being
265     /// thrown. An exception is in this state from the time it gets thrown and
266     /// not caught in a java function until `exception_clear` is called.
exception_occurred(&self) -> Result<JThrowable<'a>>267     pub fn exception_occurred(&self) -> Result<JThrowable<'a>> {
268         let throwable = jni_unchecked!(self.internal, ExceptionOccurred);
269         Ok(JThrowable::from(throwable))
270     }
271 
272     /// Print exception information to the console.
exception_describe(&self) -> Result<()>273     pub fn exception_describe(&self) -> Result<()> {
274         jni_unchecked!(self.internal, ExceptionDescribe);
275         Ok(())
276     }
277 
278     /// Clear an exception in the process of being thrown. If this is never
279     /// called, the exception will continue being thrown when control is
280     /// returned to java.
exception_clear(&self) -> Result<()>281     pub fn exception_clear(&self) -> Result<()> {
282         jni_unchecked!(self.internal, ExceptionClear);
283         Ok(())
284     }
285 
286     /// Abort the JVM with an error message.
287     #[allow(unused_variables, unreachable_code)]
fatal_error<S: Into<JNIString>>(&self, msg: S) -> !288     pub fn fatal_error<S: Into<JNIString>>(&self, msg: S) -> ! {
289         let msg = msg.into();
290         let res: Result<()> = catch!({
291             jni_unchecked!(self.internal, FatalError, msg.as_ptr());
292             unreachable!()
293         });
294 
295         panic!(res.unwrap_err());
296     }
297 
298     /// Check to see if an exception is being thrown. This only differs from
299     /// `exception_occurred` in that it doesn't return the actual thrown
300     /// exception.
exception_check(&self) -> Result<bool>301     pub fn exception_check(&self) -> Result<bool> {
302         let check = jni_unchecked!(self.internal, ExceptionCheck) == sys::JNI_TRUE;
303         Ok(check)
304     }
305 
306     /// Create a new instance of a direct java.nio.ByteBuffer.
new_direct_byte_buffer(&self, data: &mut [u8]) -> Result<JByteBuffer<'a>>307     pub fn new_direct_byte_buffer(&self, data: &mut [u8]) -> Result<JByteBuffer<'a>> {
308         let obj: JObject = jni_non_null_call!(
309             self.internal,
310             NewDirectByteBuffer,
311             data.as_mut_ptr() as *mut c_void,
312             data.len() as jlong
313         );
314         Ok(JByteBuffer::from(obj))
315     }
316 
317     /// Returns the starting address of the memory of the direct
318     /// java.nio.ByteBuffer.
get_direct_buffer_address(&self, buf: JByteBuffer) -> Result<&mut [u8]>319     pub fn get_direct_buffer_address(&self, buf: JByteBuffer) -> Result<&mut [u8]> {
320         non_null!(buf, "get_direct_buffer_address argument");
321         let ptr: *mut c_void =
322             jni_unchecked!(self.internal, GetDirectBufferAddress, buf.into_inner());
323         non_null!(ptr, "get_direct_buffer_address return value");
324         let capacity = self.get_direct_buffer_capacity(buf)?;
325         unsafe { Ok(slice::from_raw_parts_mut(ptr as *mut u8, capacity as usize)) }
326     }
327 
328     /// Returns the capacity of the direct java.nio.ByteBuffer.
get_direct_buffer_capacity(&self, buf: JByteBuffer) -> Result<jlong>329     pub fn get_direct_buffer_capacity(&self, buf: JByteBuffer) -> Result<jlong> {
330         let capacity = jni_unchecked!(self.internal, GetDirectBufferCapacity, buf.into_inner());
331         match capacity {
332             -1 => Err(Error::JniCall(JniError::Unknown)),
333             _ => Ok(capacity),
334         }
335     }
336 
337     /// Turns an object into a global ref. This has the benefit of removing the
338     /// lifetime bounds since it's guaranteed to not get GC'd by java. It
339     /// releases the GC pin upon being dropped.
new_global_ref<O>(&self, obj: O) -> Result<GlobalRef> where O: Into<JObject<'a>>,340     pub fn new_global_ref<O>(&self, obj: O) -> Result<GlobalRef>
341     where
342         O: Into<JObject<'a>>,
343     {
344         let new_ref: JObject =
345             jni_unchecked!(self.internal, NewGlobalRef, obj.into().into_inner()).into();
346         let global = unsafe { GlobalRef::from_raw(self.get_java_vm()?, new_ref.into_inner()) };
347         Ok(global)
348     }
349 
350     /// Create a new local ref to an object.
351     ///
352     /// Note that the object passed to this is *already* a local ref. This
353     /// creates yet another reference to it, which is most likely not what you
354     /// want.
new_local_ref<T>(&self, obj: JObject<'a>) -> Result<JObject<'a>>355     pub fn new_local_ref<T>(&self, obj: JObject<'a>) -> Result<JObject<'a>> {
356         let local: JObject = jni_unchecked!(self.internal, NewLocalRef, obj.into_inner()).into();
357         Ok(local)
358     }
359 
360     /// Creates a new auto-deleted local reference.
361     ///
362     /// See also [`with_local_frame`](struct.JNIEnv.html#method.with_local_frame) method that
363     /// can be more convenient when you create a _bounded_ number of local references
364     /// but cannot rely on automatic de-allocation (e.g., in case of recursion, deep call stacks,
365     /// [permanently-attached](struct.JavaVM.html#attaching-native-threads) native threads, etc.).
auto_local<'b, O>(&'b self, obj: O) -> AutoLocal<'a, 'b> where O: Into<JObject<'a>>,366     pub fn auto_local<'b, O>(&'b self, obj: O) -> AutoLocal<'a, 'b>
367     where
368         O: Into<JObject<'a>>,
369     {
370         AutoLocal::new(self, obj.into())
371     }
372 
373     /// Deletes the local reference.
374     ///
375     /// Local references are valid for the duration of a native method call.
376     /// They are
377     /// freed automatically after the native method returns. Each local
378     /// reference costs
379     /// some amount of Java Virtual Machine resource. Programmers need to make
380     /// sure that
381     /// native methods do not excessively allocate local references. Although
382     /// local
383     /// references are automatically freed after the native method returns to
384     /// Java,
385     /// excessive allocation of local references may cause the VM to run out of
386     /// memory
387     /// during the execution of a native method.
388     ///
389     /// In most cases it is better to use `AutoLocal` (see `auto_local` method)
390     /// or `with_local_frame` instead of direct `delete_local_ref` calls.
delete_local_ref(&self, obj: JObject) -> Result<()>391     pub fn delete_local_ref(&self, obj: JObject) -> Result<()> {
392         jni_unchecked!(self.internal, DeleteLocalRef, obj.into_inner());
393         Ok(())
394     }
395 
396     /// Creates a new local reference frame, in which at least a given number
397     /// of local references can be created.
398     ///
399     /// Returns `Err` on failure, with a pending `OutOfMemoryError`.
400     ///
401     /// Prefer to use [`with_local_frame`](struct.JNIEnv.html#method.with_local_frame) instead of
402     /// direct `push_local_frame`/`pop_local_frame` calls.
403     ///
404     /// See also [`auto_local`](struct.JNIEnv.html#method.auto_local) method
405     /// and `AutoLocal` type — that approach can be more convenient in loops.
push_local_frame(&self, capacity: i32) -> Result<()>406     pub fn push_local_frame(&self, capacity: i32) -> Result<()> {
407         // This method is safe to call in case of pending exceptions (see chapter 2 of the spec)
408         let res = jni_unchecked!(self.internal, PushLocalFrame, capacity);
409         jni_error_code_to_result(res)
410     }
411 
412     /// Pops off the current local reference frame, frees all the local
413     /// references allocated on the current stack frame, except the `result`,
414     /// which is returned from this function and remains valid.
415     ///
416     /// The resulting `JObject` will be `NULL` iff `result` is `NULL`.
pop_local_frame(&self, result: JObject<'a>) -> Result<JObject<'a>>417     pub fn pop_local_frame(&self, result: JObject<'a>) -> Result<JObject<'a>> {
418         // This method is safe to call in case of pending exceptions (see chapter 2 of the spec)
419         Ok(jni_unchecked!(self.internal, PopLocalFrame, result.into_inner()).into())
420     }
421 
422     /// Executes the given function in a new local reference frame, in which at least a given number
423     /// of references can be created. Once this method returns, all references allocated
424     /// in the frame are freed, except the one that the function returns, which remains valid.
425     ///
426     /// If _no_ new frames can be allocated, returns `Err` with a pending `OutOfMemoryError`.
427     ///
428     /// See also [`auto_local`](struct.JNIEnv.html#method.auto_local) method
429     /// and `AutoLocal` type - that approach can be more convenient in loops.
with_local_frame<F>(&self, capacity: i32, f: F) -> Result<JObject<'a>> where F: FnOnce() -> Result<JObject<'a>>,430     pub fn with_local_frame<F>(&self, capacity: i32, f: F) -> Result<JObject<'a>>
431     where
432         F: FnOnce() -> Result<JObject<'a>>,
433     {
434         self.push_local_frame(capacity)?;
435         let res = f();
436         match res {
437             Ok(obj) => self.pop_local_frame(obj),
438             Err(e) => {
439                 self.pop_local_frame(JObject::null())?;
440                 Err(e)
441             }
442         }
443     }
444 
445     /// Allocates a new object from a class descriptor without running a
446     /// constructor.
alloc_object<'c, T>(&self, class: T) -> Result<JObject<'a>> where T: Desc<'a, JClass<'c>>,447     pub fn alloc_object<'c, T>(&self, class: T) -> Result<JObject<'a>>
448     where
449         T: Desc<'a, JClass<'c>>,
450     {
451         let class = class.lookup(self)?;
452         Ok(jni_non_null_call!(
453             self.internal,
454             AllocObject,
455             class.into_inner()
456         ))
457     }
458 
459     /// Common functionality for finding methods.
460     #[allow(clippy::redundant_closure_call)]
get_method_id_base<'c, T, U, V, C, R>( &self, class: T, name: U, sig: V, get_method: C, ) -> Result<R> where T: Desc<'a, JClass<'c>>, U: Into<JNIString>, V: Into<JNIString>, C: for<'d> Fn(&JClass<'d>, &JNIString, &JNIString) -> Result<R>,461     fn get_method_id_base<'c, T, U, V, C, R>(
462         &self,
463         class: T,
464         name: U,
465         sig: V,
466         get_method: C,
467     ) -> Result<R>
468     where
469         T: Desc<'a, JClass<'c>>,
470         U: Into<JNIString>,
471         V: Into<JNIString>,
472         C: for<'d> Fn(&JClass<'d>, &JNIString, &JNIString) -> Result<R>,
473     {
474         let class = class.lookup(self)?;
475         let ffi_name = name.into();
476         let sig = sig.into();
477 
478         let res: Result<R> = catch!({ get_method(&class, &ffi_name, &sig) });
479 
480         match res {
481             Ok(m) => Ok(m),
482             Err(e) => match e {
483                 Error::NullPtr(_) => {
484                     let name: String = ffi_name.into();
485                     let sig: String = sig.into();
486                     Err(Error::MethodNotFound { name, sig })
487                 }
488                 _ => Err(e),
489             },
490         }
491     }
492 
493     /// Look up a method by class descriptor, name, and
494     /// signature.
495     ///
496     /// # Example
497     /// ```rust,ignore
498     /// let method_id: JMethodID =
499     ///     env.get_method_id("java/lang/String", "substring", "(II)Ljava/lang/String;");
500     /// ```
get_method_id<'c, T, U, V>(&self, class: T, name: U, sig: V) -> Result<JMethodID<'a>> where T: Desc<'a, JClass<'c>>, U: Into<JNIString>, V: Into<JNIString>,501     pub fn get_method_id<'c, T, U, V>(&self, class: T, name: U, sig: V) -> Result<JMethodID<'a>>
502     where
503         T: Desc<'a, JClass<'c>>,
504         U: Into<JNIString>,
505         V: Into<JNIString>,
506     {
507         self.get_method_id_base(class, name, sig, |class, name, sig| {
508             Ok(jni_non_null_call!(
509                 self.internal,
510                 GetMethodID,
511                 class.into_inner(),
512                 name.as_ptr(),
513                 sig.as_ptr()
514             ))
515         })
516     }
517 
518     /// Look up a static method by class descriptor, name, and
519     /// signature.
520     ///
521     /// # Example
522     /// ```rust,ignore
523     /// let method_id: JMethodID =
524     ///     env.get_static_method_id("java/lang/String", "valueOf", "(I)Ljava/lang/String;");
525     /// ```
get_static_method_id<'c, T, U, V>( &self, class: T, name: U, sig: V, ) -> Result<JStaticMethodID<'a>> where T: Desc<'a, JClass<'c>>, U: Into<JNIString>, V: Into<JNIString>,526     pub fn get_static_method_id<'c, T, U, V>(
527         &self,
528         class: T,
529         name: U,
530         sig: V,
531     ) -> Result<JStaticMethodID<'a>>
532     where
533         T: Desc<'a, JClass<'c>>,
534         U: Into<JNIString>,
535         V: Into<JNIString>,
536     {
537         self.get_method_id_base(class, name, sig, |class, name, sig| {
538             Ok(jni_non_null_call!(
539                 self.internal,
540                 GetStaticMethodID,
541                 class.into_inner(),
542                 name.as_ptr(),
543                 sig.as_ptr()
544             ))
545         })
546     }
547 
548     /// Look up the field ID for a class/name/type combination.
549     ///
550     /// # Example
551     /// ```rust,ignore
552     /// let field_id = env.get_field_id("com/my/Class", "intField", "I");
553     /// ```
get_field_id<'c, T, U, V>(&self, class: T, name: U, sig: V) -> Result<JFieldID<'a>> where T: Desc<'a, JClass<'c>>, U: Into<JNIString>, V: Into<JNIString>,554     pub fn get_field_id<'c, T, U, V>(&self, class: T, name: U, sig: V) -> Result<JFieldID<'a>>
555     where
556         T: Desc<'a, JClass<'c>>,
557         U: Into<JNIString>,
558         V: Into<JNIString>,
559     {
560         let class = class.lookup(self)?;
561         let ffi_name = name.into();
562         let ffi_sig = sig.into();
563 
564         let res: Result<JFieldID> = catch!({
565             Ok(jni_non_null_call!(
566                 self.internal,
567                 GetFieldID,
568                 class.into_inner(),
569                 ffi_name.as_ptr(),
570                 ffi_sig.as_ptr()
571             ))
572         });
573 
574         match res {
575             Ok(m) => Ok(m),
576             Err(e) => match e {
577                 Error::NullPtr(_) => {
578                     let name: String = ffi_name.into();
579                     let sig: String = ffi_sig.into();
580                     Err(Error::FieldNotFound { name, sig })
581                 }
582                 _ => Err(e),
583             },
584         }
585     }
586 
587     /// Look up the static field ID for a class/name/type combination.
588     ///
589     /// # Example
590     /// ```rust,ignore
591     /// let field_id = env.get_static_field_id("com/my/Class", "intField", "I");
592     /// ```
get_static_field_id<'c, T, U, V>( &self, class: T, name: U, sig: V, ) -> Result<JStaticFieldID<'a>> where T: Desc<'a, JClass<'c>>, U: Into<JNIString>, V: Into<JNIString>,593     pub fn get_static_field_id<'c, T, U, V>(
594         &self,
595         class: T,
596         name: U,
597         sig: V,
598     ) -> Result<JStaticFieldID<'a>>
599     where
600         T: Desc<'a, JClass<'c>>,
601         U: Into<JNIString>,
602         V: Into<JNIString>,
603     {
604         let class = class.lookup(self)?;
605         let ffi_name = name.into();
606         let ffi_sig = sig.into();
607 
608         let res: Result<JStaticFieldID> = catch!({
609             Ok(jni_non_null_call!(
610                 self.internal,
611                 GetStaticFieldID,
612                 class.into_inner(),
613                 ffi_name.as_ptr(),
614                 ffi_sig.as_ptr()
615             ))
616         });
617 
618         match res {
619             Ok(m) => Ok(m),
620             Err(e) => match e {
621                 Error::NullPtr(_) => {
622                     let name: String = ffi_name.into();
623                     let sig: String = ffi_sig.into();
624                     Err(Error::FieldNotFound { name, sig })
625                 }
626                 _ => Err(e),
627             },
628         }
629     }
630 
631     /// Get the class for an object.
get_object_class<'b, O>(&self, obj: O) -> Result<JClass<'a>> where O: Into<JObject<'b>>,632     pub fn get_object_class<'b, O>(&self, obj: O) -> Result<JClass<'a>>
633     where
634         O: Into<JObject<'b>>,
635     {
636         let obj = obj.into();
637         non_null!(obj, "get_object_class");
638         Ok(jni_unchecked!(self.internal, GetObjectClass, obj.into_inner()).into())
639     }
640 
641     /// Call a static method in an unsafe manner. This does nothing to check
642     /// whether the method is valid to call on the class, whether the return
643     /// type is correct, or whether the number of args is valid for the method.
644     ///
645     /// Under the hood, this simply calls the `CallStatic<Type>MethodA` method
646     /// with the provided arguments.
call_static_method_unchecked<'c, 'm, T, U>( &self, class: T, method_id: U, ret: JavaType, args: &[JValue], ) -> Result<JValue<'a>> where T: Desc<'a, JClass<'c>>, U: Desc<'a, JStaticMethodID<'m>>,647     pub fn call_static_method_unchecked<'c, 'm, T, U>(
648         &self,
649         class: T,
650         method_id: U,
651         ret: JavaType,
652         args: &[JValue],
653     ) -> Result<JValue<'a>>
654     where
655         T: Desc<'a, JClass<'c>>,
656         U: Desc<'a, JStaticMethodID<'m>>,
657     {
658         let class = class.lookup(self)?;
659 
660         let method_id = method_id.lookup(self)?.into_inner();
661 
662         let class = class.into_inner();
663         let args: Vec<jvalue> = args.iter().map(|v| v.to_jni()).collect();
664         let jni_args = args.as_ptr();
665 
666         // TODO clean this up
667         Ok(match ret {
668             JavaType::Object(_) | JavaType::Array(_) => {
669                 let obj: JObject = jni_non_void_call!(
670                     self.internal,
671                     CallStaticObjectMethodA,
672                     class,
673                     method_id,
674                     jni_args
675                 )
676                 .into();
677                 obj.into()
678             }
679             // JavaType::Object
680             JavaType::Method(_) => unimplemented!(),
681             JavaType::Primitive(p) => match p {
682                 Primitive::Boolean => jni_non_void_call!(
683                     self.internal,
684                     CallStaticBooleanMethodA,
685                     class,
686                     method_id,
687                     jni_args
688                 )
689                 .into(),
690                 Primitive::Char => jni_non_void_call!(
691                     self.internal,
692                     CallStaticCharMethodA,
693                     class,
694                     method_id,
695                     jni_args
696                 )
697                 .into(),
698                 Primitive::Short => jni_non_void_call!(
699                     self.internal,
700                     CallStaticShortMethodA,
701                     class,
702                     method_id,
703                     jni_args
704                 )
705                 .into(),
706                 Primitive::Int => jni_non_void_call!(
707                     self.internal,
708                     CallStaticIntMethodA,
709                     class,
710                     method_id,
711                     jni_args
712                 )
713                 .into(),
714                 Primitive::Long => jni_non_void_call!(
715                     self.internal,
716                     CallStaticLongMethodA,
717                     class,
718                     method_id,
719                     jni_args
720                 )
721                 .into(),
722                 Primitive::Float => jni_non_void_call!(
723                     self.internal,
724                     CallStaticFloatMethodA,
725                     class,
726                     method_id,
727                     jni_args
728                 )
729                 .into(),
730                 Primitive::Double => jni_non_void_call!(
731                     self.internal,
732                     CallStaticDoubleMethodA,
733                     class,
734                     method_id,
735                     jni_args
736                 )
737                 .into(),
738                 Primitive::Byte => jni_non_void_call!(
739                     self.internal,
740                     CallStaticByteMethodA,
741                     class,
742                     method_id,
743                     jni_args
744                 )
745                 .into(),
746                 Primitive::Void => {
747                     jni_void_call!(
748                         self.internal,
749                         CallStaticVoidMethodA,
750                         class,
751                         method_id,
752                         jni_args
753                     );
754                     return Ok(JValue::Void);
755                 }
756             }, // JavaType::Primitive
757         }) // match parsed.ret
758     }
759 
760     /// Call an object method in an unsafe manner. This does nothing to check
761     /// whether the method is valid to call on the object, whether the return
762     /// type is correct, or whether the number of args is valid for the method.
763     ///
764     /// Under the hood, this simply calls the `Call<Type>MethodA` method with
765     /// the provided arguments.
call_method_unchecked<'m, O, T>( &self, obj: O, method_id: T, ret: JavaType, args: &[JValue], ) -> Result<JValue<'a>> where O: Into<JObject<'a>>, T: Desc<'a, JMethodID<'m>>,766     pub fn call_method_unchecked<'m, O, T>(
767         &self,
768         obj: O,
769         method_id: T,
770         ret: JavaType,
771         args: &[JValue],
772     ) -> Result<JValue<'a>>
773     where
774         O: Into<JObject<'a>>,
775         T: Desc<'a, JMethodID<'m>>,
776     {
777         let method_id = method_id.lookup(self)?.into_inner();
778 
779         let obj = obj.into().into_inner();
780 
781         let args: Vec<jvalue> = args.iter().map(|v| v.to_jni()).collect();
782         let jni_args = args.as_ptr();
783 
784         // TODO clean this up
785         Ok(match ret {
786             JavaType::Object(_) | JavaType::Array(_) => {
787                 let obj: JObject =
788                     jni_non_void_call!(self.internal, CallObjectMethodA, obj, method_id, jni_args)
789                         .into();
790                 obj.into()
791             }
792             // JavaType::Object
793             JavaType::Method(_) => unimplemented!(),
794             JavaType::Primitive(p) => match p {
795                 Primitive::Boolean => {
796                     jni_non_void_call!(self.internal, CallBooleanMethodA, obj, method_id, jni_args)
797                         .into()
798                 }
799                 Primitive::Char => {
800                     jni_non_void_call!(self.internal, CallCharMethodA, obj, method_id, jni_args)
801                         .into()
802                 }
803                 Primitive::Short => {
804                     jni_non_void_call!(self.internal, CallShortMethodA, obj, method_id, jni_args)
805                         .into()
806                 }
807                 Primitive::Int => {
808                     jni_non_void_call!(self.internal, CallIntMethodA, obj, method_id, jni_args)
809                         .into()
810                 }
811                 Primitive::Long => {
812                     jni_non_void_call!(self.internal, CallLongMethodA, obj, method_id, jni_args)
813                         .into()
814                 }
815                 Primitive::Float => {
816                     jni_non_void_call!(self.internal, CallFloatMethodA, obj, method_id, jni_args)
817                         .into()
818                 }
819                 Primitive::Double => {
820                     jni_non_void_call!(self.internal, CallDoubleMethodA, obj, method_id, jni_args)
821                         .into()
822                 }
823                 Primitive::Byte => {
824                     jni_non_void_call!(self.internal, CallByteMethodA, obj, method_id, jni_args)
825                         .into()
826                 }
827                 Primitive::Void => {
828                     jni_void_call!(self.internal, CallVoidMethodA, obj, method_id, jni_args);
829                     return Ok(JValue::Void);
830                 }
831             }, // JavaType::Primitive
832         }) // match parsed.ret
833     }
834 
835     /// Calls an object method safely. This comes with a number of
836     /// lookups/checks. It
837     ///
838     /// * Parses the type signature to find the number of arguments and return
839     ///   type
840     /// * Looks up the JClass for the given object.
841     /// * Looks up the JMethodID for the class/name/signature combination
842     /// * Ensures that the number of args matches the signature
843     /// * Calls `call_method_unchecked` with the verified safe arguments.
844     ///
845     /// Note: this may cause a java exception if the arguments are the wrong
846     /// type, in addition to if the method itself throws.
call_method<O, S, T>( &self, obj: O, name: S, sig: T, args: &[JValue], ) -> Result<JValue<'a>> where O: Into<JObject<'a>>, S: Into<JNIString>, T: Into<JNIString> + AsRef<str>,847     pub fn call_method<O, S, T>(
848         &self,
849         obj: O,
850         name: S,
851         sig: T,
852         args: &[JValue],
853     ) -> Result<JValue<'a>>
854     where
855         O: Into<JObject<'a>>,
856         S: Into<JNIString>,
857         T: Into<JNIString> + AsRef<str>,
858     {
859         let obj = obj.into();
860         non_null!(obj, "call_method obj argument");
861 
862         // parse the signature
863         let parsed = TypeSignature::from_str(sig.as_ref())?;
864         if parsed.args.len() != args.len() {
865             return Err(Error::InvalidArgList(parsed));
866         }
867 
868         let class = self.auto_local(self.get_object_class(obj)?);
869 
870         self.call_method_unchecked(obj, (&class, name, sig), parsed.ret, args)
871     }
872 
873     /// Calls a static method safely. This comes with a number of
874     /// lookups/checks. It
875     ///
876     /// * Parses the type signature to find the number of arguments and return
877     ///   type
878     /// * Looks up the JMethodID for the class/name/signature combination
879     /// * Ensures that the number of args matches the signature
880     /// * Calls `call_method_unchecked` with the verified safe arguments.
881     ///
882     /// Note: this may cause a java exception if the arguments are the wrong
883     /// type, in addition to if the method itself throws.
call_static_method<'c, T, U, V>( &self, class: T, name: U, sig: V, args: &[JValue], ) -> Result<JValue<'a>> where T: Desc<'a, JClass<'c>>, U: Into<JNIString>, V: Into<JNIString> + AsRef<str>,884     pub fn call_static_method<'c, T, U, V>(
885         &self,
886         class: T,
887         name: U,
888         sig: V,
889         args: &[JValue],
890     ) -> Result<JValue<'a>>
891     where
892         T: Desc<'a, JClass<'c>>,
893         U: Into<JNIString>,
894         V: Into<JNIString> + AsRef<str>,
895     {
896         let parsed = TypeSignature::from_str(&sig)?;
897         if parsed.args.len() != args.len() {
898             return Err(Error::InvalidArgList(parsed));
899         }
900 
901         // go ahead and look up the class since it's already Copy,
902         // and we'll need that for the next call.
903         let class = class.lookup(self)?;
904 
905         self.call_static_method_unchecked(class, (class, name, sig), parsed.ret, args)
906     }
907 
908     /// Create a new object using a constructor. This is done safely using
909     /// checks similar to those in `call_static_method`.
new_object<'c, T, U>( &self, class: T, ctor_sig: U, ctor_args: &[JValue], ) -> Result<JObject<'a>> where T: Desc<'a, JClass<'c>>, U: Into<JNIString> + AsRef<str>,910     pub fn new_object<'c, T, U>(
911         &self,
912         class: T,
913         ctor_sig: U,
914         ctor_args: &[JValue],
915     ) -> Result<JObject<'a>>
916     where
917         T: Desc<'a, JClass<'c>>,
918         U: Into<JNIString> + AsRef<str>,
919     {
920         // parse the signature
921         let parsed = TypeSignature::from_str(&ctor_sig)?;
922 
923         if parsed.args.len() != ctor_args.len() {
924             return Err(Error::InvalidArgList(parsed));
925         }
926 
927         if parsed.ret != JavaType::Primitive(Primitive::Void) {
928             return Err(Error::InvalidCtorReturn);
929         }
930 
931         // build strings
932         let class = class.lookup(self)?;
933 
934         let method_id: JMethodID = (class, ctor_sig).lookup(self)?;
935 
936         self.new_object_unchecked(class, method_id, ctor_args)
937     }
938 
939     /// Create a new object using a constructor. Arguments aren't checked
940     /// because
941     /// of the `JMethodID` usage.
new_object_unchecked<'c, T>( &self, class: T, ctor_id: JMethodID, ctor_args: &[JValue], ) -> Result<JObject<'a>> where T: Desc<'a, JClass<'c>>,942     pub fn new_object_unchecked<'c, T>(
943         &self,
944         class: T,
945         ctor_id: JMethodID,
946         ctor_args: &[JValue],
947     ) -> Result<JObject<'a>>
948     where
949         T: Desc<'a, JClass<'c>>,
950     {
951         let class = class.lookup(self)?;
952 
953         let jni_args: Vec<jvalue> = ctor_args.iter().map(|v| v.to_jni()).collect();
954         let jni_args = jni_args.as_ptr();
955 
956         Ok(jni_non_null_call!(
957             self.internal,
958             NewObjectA,
959             class.into_inner(),
960             ctor_id.into_inner(),
961             jni_args
962         ))
963     }
964 
965     /// Cast a JObject to a `JList`. This won't throw exceptions or return errors
966     /// in the event that the object isn't actually a list, but the methods on
967     /// the resulting map object will.
get_list(&self, obj: JObject<'a>) -> Result<JList<'a, '_>>968     pub fn get_list(&self, obj: JObject<'a>) -> Result<JList<'a, '_>> {
969         non_null!(obj, "get_list obj argument");
970         JList::from_env(self, obj)
971     }
972 
973     /// Cast a JObject to a JMap. This won't throw exceptions or return errors
974     /// in the event that the object isn't actually a map, but the methods on
975     /// the resulting map object will.
get_map(&self, obj: JObject<'a>) -> Result<JMap<'a, '_>>976     pub fn get_map(&self, obj: JObject<'a>) -> Result<JMap<'a, '_>> {
977         non_null!(obj, "get_map obj argument");
978         JMap::from_env(self, obj)
979     }
980 
981     /// Get a JavaStr from a JString. This allows conversions from java string
982     /// objects to rust strings.
983     ///
984     /// This entails a call to `GetStringUTFChars` and only decodes java's
985     /// modified UTF-8 format on conversion to a rust-compatible string.
get_string(&self, obj: JString<'a>) -> Result<JavaStr<'a, '_>>986     pub fn get_string(&self, obj: JString<'a>) -> Result<JavaStr<'a, '_>> {
987         non_null!(obj, "get_string obj argument");
988         JavaStr::from_env(self, obj)
989     }
990 
991     /// Get a pointer to the character array beneath a JString.
992     ///
993     /// Array contains Java's modified UTF-8.
994     ///
995     /// # Attention
996     /// This will leak memory if `release_string_utf_chars` is never called.
get_string_utf_chars(&self, obj: JString) -> Result<*const c_char>997     pub fn get_string_utf_chars(&self, obj: JString) -> Result<*const c_char> {
998         non_null!(obj, "get_string_utf_chars obj argument");
999         let ptr: *const c_char = jni_non_null_call!(
1000             self.internal,
1001             GetStringUTFChars,
1002             obj.into_inner(),
1003             ::std::ptr::null::<jboolean>() as *mut jboolean
1004         );
1005         Ok(ptr)
1006     }
1007 
1008     /// Unpin the array returned by `get_string_utf_chars`.
1009     // It is safe to dereference a pointer that comes from `get_string_utf_chars`.
1010     #[allow(clippy::not_unsafe_ptr_arg_deref)]
release_string_utf_chars(&self, obj: JString, arr: *const c_char) -> Result<()>1011     pub fn release_string_utf_chars(&self, obj: JString, arr: *const c_char) -> Result<()> {
1012         non_null!(obj, "release_string_utf_chars obj argument");
1013         // This method is safe to call in case of pending exceptions (see the chapter 2 of the spec)
1014         jni_unchecked!(self.internal, ReleaseStringUTFChars, obj.into_inner(), arr);
1015         Ok(())
1016     }
1017 
1018     /// Create a new java string object from a rust string. This requires a
1019     /// re-encoding of rusts *real* UTF-8 strings to java's modified UTF-8
1020     /// format.
new_string<S: Into<JNIString>>(&self, from: S) -> Result<JString<'a>>1021     pub fn new_string<S: Into<JNIString>>(&self, from: S) -> Result<JString<'a>> {
1022         let ffi_str = from.into();
1023         Ok(jni_non_null_call!(
1024             self.internal,
1025             NewStringUTF,
1026             ffi_str.as_ptr()
1027         ))
1028     }
1029 
1030     /// Get the length of a java array
get_array_length(&self, array: jarray) -> Result<jsize>1031     pub fn get_array_length(&self, array: jarray) -> Result<jsize> {
1032         non_null!(array, "get_array_length array argument");
1033         let len: jsize = jni_unchecked!(self.internal, GetArrayLength, array);
1034         Ok(len)
1035     }
1036 
1037     /// Construct a new array holding objects in class `element_class`.
1038     /// All elements are initially set to `initial_element`.
1039     ///
1040     /// This function returns a local reference, that must not be allocated
1041     /// excessively.
1042     /// See [Java documentation][1] for details.
1043     ///
1044     /// [1]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references
new_object_array<'c, T, U>( &self, length: jsize, element_class: T, initial_element: U, ) -> Result<jobjectArray> where T: Desc<'a, JClass<'c>>, U: Into<JObject<'a>>,1045     pub fn new_object_array<'c, T, U>(
1046         &self,
1047         length: jsize,
1048         element_class: T,
1049         initial_element: U,
1050     ) -> Result<jobjectArray>
1051     where
1052         T: Desc<'a, JClass<'c>>,
1053         U: Into<JObject<'a>>,
1054     {
1055         let class = element_class.lookup(self)?;
1056         Ok(jni_non_null_call!(
1057             self.internal,
1058             NewObjectArray,
1059             length,
1060             class.into_inner(),
1061             initial_element.into().into_inner()
1062         ))
1063     }
1064 
1065     /// Returns an element of the `jobjectArray` array.
get_object_array_element( &self, array: jobjectArray, index: jsize, ) -> Result<JObject<'a>>1066     pub fn get_object_array_element(
1067         &self,
1068         array: jobjectArray,
1069         index: jsize,
1070     ) -> Result<JObject<'a>> {
1071         non_null!(array, "get_object_array_element array argument");
1072         Ok(jni_non_void_call!(self.internal, GetObjectArrayElement, array, index).into())
1073     }
1074 
1075     /// Sets an element of the `jobjectArray` array.
set_object_array_element<O>( &self, array: jobjectArray, index: jsize, value: O, ) -> Result<()> where O: Into<JObject<'a>>,1076     pub fn set_object_array_element<O>(
1077         &self,
1078         array: jobjectArray,
1079         index: jsize,
1080         value: O,
1081     ) -> Result<()>
1082     where
1083         O: Into<JObject<'a>>,
1084     {
1085         non_null!(array, "set_object_array_element array argument");
1086         jni_void_call!(
1087             self.internal,
1088             SetObjectArrayElement,
1089             array,
1090             index,
1091             value.into().into_inner()
1092         );
1093         Ok(())
1094     }
1095 
1096     /// Create a new java byte array from a rust byte slice.
byte_array_from_slice(&self, buf: &[u8]) -> Result<jbyteArray>1097     pub fn byte_array_from_slice(&self, buf: &[u8]) -> Result<jbyteArray> {
1098         let length = buf.len() as i32;
1099         let bytes: jbyteArray = self.new_byte_array(length)?;
1100         jni_unchecked!(
1101             self.internal,
1102             SetByteArrayRegion,
1103             bytes,
1104             0,
1105             length,
1106             buf.as_ptr() as *const i8
1107         );
1108         Ok(bytes)
1109     }
1110 
1111     /// Converts a java byte array to a rust vector of bytes.
convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>>1112     pub fn convert_byte_array(&self, array: jbyteArray) -> Result<Vec<u8>> {
1113         non_null!(array, "convert_byte_array array argument");
1114         let length = jni_non_void_call!(self.internal, GetArrayLength, array);
1115         let mut vec = vec![0u8; length as usize];
1116         jni_unchecked!(
1117             self.internal,
1118             GetByteArrayRegion,
1119             array,
1120             0,
1121             length,
1122             vec.as_mut_ptr() as *mut i8
1123         );
1124         Ok(vec)
1125     }
1126 
1127     /// Create a new java boolean array of supplied length.
new_boolean_array(&self, length: jsize) -> Result<jbooleanArray>1128     pub fn new_boolean_array(&self, length: jsize) -> Result<jbooleanArray> {
1129         let array: jbooleanArray = jni_non_null_call!(self.internal, NewBooleanArray, length);
1130         Ok(array)
1131     }
1132 
1133     /// Create a new java byte array of supplied length.
new_byte_array(&self, length: jsize) -> Result<jbyteArray>1134     pub fn new_byte_array(&self, length: jsize) -> Result<jbyteArray> {
1135         let array: jbyteArray = jni_non_null_call!(self.internal, NewByteArray, length);
1136         Ok(array)
1137     }
1138 
1139     /// Create a new java char array of supplied length.
new_char_array(&self, length: jsize) -> Result<jcharArray>1140     pub fn new_char_array(&self, length: jsize) -> Result<jcharArray> {
1141         let array: jcharArray = jni_non_null_call!(self.internal, NewCharArray, length);
1142         Ok(array)
1143     }
1144 
1145     /// Create a new java short array of supplied length.
new_short_array(&self, length: jsize) -> Result<jshortArray>1146     pub fn new_short_array(&self, length: jsize) -> Result<jshortArray> {
1147         let array: jshortArray = jni_non_null_call!(self.internal, NewShortArray, length);
1148         Ok(array)
1149     }
1150 
1151     /// Create a new java int array of supplied length.
new_int_array(&self, length: jsize) -> Result<jintArray>1152     pub fn new_int_array(&self, length: jsize) -> Result<jintArray> {
1153         let array: jintArray = jni_non_null_call!(self.internal, NewIntArray, length);
1154         Ok(array)
1155     }
1156 
1157     /// Create a new java long array of supplied length.
new_long_array(&self, length: jsize) -> Result<jlongArray>1158     pub fn new_long_array(&self, length: jsize) -> Result<jlongArray> {
1159         let array: jlongArray = jni_non_null_call!(self.internal, NewLongArray, length);
1160         Ok(array)
1161     }
1162 
1163     /// Create a new java float array of supplied length.
new_float_array(&self, length: jsize) -> Result<jfloatArray>1164     pub fn new_float_array(&self, length: jsize) -> Result<jfloatArray> {
1165         let array: jfloatArray = jni_non_null_call!(self.internal, NewFloatArray, length);
1166         Ok(array)
1167     }
1168 
1169     /// Create a new java double array of supplied length.
new_double_array(&self, length: jsize) -> Result<jdoubleArray>1170     pub fn new_double_array(&self, length: jsize) -> Result<jdoubleArray> {
1171         let array: jdoubleArray = jni_non_null_call!(self.internal, NewDoubleArray, length);
1172         Ok(array)
1173     }
1174 
1175     /// Copy elements of the java boolean array from the `start` index to the
1176     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1177     ///
1178     /// # Errors
1179     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1180     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1181     /// and `Err` is returned.
1182     ///
1183     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_boolean_array_region( &self, array: jbooleanArray, start: jsize, buf: &mut [jboolean], ) -> Result<()>1184     pub fn get_boolean_array_region(
1185         &self,
1186         array: jbooleanArray,
1187         start: jsize,
1188         buf: &mut [jboolean],
1189     ) -> Result<()> {
1190         non_null!(array, "get_boolean_array_region array argument");
1191         jni_void_call!(
1192             self.internal,
1193             GetBooleanArrayRegion,
1194             array,
1195             start,
1196             buf.len() as jsize,
1197             buf.as_mut_ptr()
1198         );
1199         Ok(())
1200     }
1201 
1202     /// Copy elements of the java byte array from the `start` index to the `buf`
1203     /// slice. The number of copied elements is equal to the `buf` length.
1204     ///
1205     /// # Errors
1206     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1207     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1208     /// and `Err` is returned.
1209     ///
1210     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_byte_array_region( &self, array: jbyteArray, start: jsize, buf: &mut [jbyte], ) -> Result<()>1211     pub fn get_byte_array_region(
1212         &self,
1213         array: jbyteArray,
1214         start: jsize,
1215         buf: &mut [jbyte],
1216     ) -> Result<()> {
1217         non_null!(array, "get_byte_array_region array argument");
1218         jni_void_call!(
1219             self.internal,
1220             GetByteArrayRegion,
1221             array,
1222             start,
1223             buf.len() as jsize,
1224             buf.as_mut_ptr()
1225         );
1226         Ok(())
1227     }
1228 
1229     /// Copy elements of the java char array from the `start` index to the
1230     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1231     ///
1232     /// # Errors
1233     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1234     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1235     /// and `Err` is returned.
1236     ///
1237     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_char_array_region( &self, array: jcharArray, start: jsize, buf: &mut [jchar], ) -> Result<()>1238     pub fn get_char_array_region(
1239         &self,
1240         array: jcharArray,
1241         start: jsize,
1242         buf: &mut [jchar],
1243     ) -> Result<()> {
1244         non_null!(array, "get_char_array_region array argument");
1245         jni_void_call!(
1246             self.internal,
1247             GetCharArrayRegion,
1248             array,
1249             start,
1250             buf.len() as jsize,
1251             buf.as_mut_ptr()
1252         );
1253         Ok(())
1254     }
1255 
1256     /// Copy elements of the java short array from the `start` index to the
1257     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1258     ///
1259     /// # Errors
1260     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1261     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1262     /// and `Err` is returned.
1263     ///
1264     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_short_array_region( &self, array: jshortArray, start: jsize, buf: &mut [jshort], ) -> Result<()>1265     pub fn get_short_array_region(
1266         &self,
1267         array: jshortArray,
1268         start: jsize,
1269         buf: &mut [jshort],
1270     ) -> Result<()> {
1271         non_null!(array, "get_short_array_region array argument");
1272         jni_void_call!(
1273             self.internal,
1274             GetShortArrayRegion,
1275             array,
1276             start,
1277             buf.len() as jsize,
1278             buf.as_mut_ptr()
1279         );
1280         Ok(())
1281     }
1282 
1283     /// Copy elements of the java int array from the `start` index to the
1284     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1285     ///
1286     /// # Errors
1287     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1288     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1289     /// and `Err` is returned.
1290     ///
1291     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_int_array_region( &self, array: jintArray, start: jsize, buf: &mut [jint], ) -> Result<()>1292     pub fn get_int_array_region(
1293         &self,
1294         array: jintArray,
1295         start: jsize,
1296         buf: &mut [jint],
1297     ) -> Result<()> {
1298         non_null!(array, "get_int_array_region array argument");
1299         jni_void_call!(
1300             self.internal,
1301             GetIntArrayRegion,
1302             array,
1303             start,
1304             buf.len() as jsize,
1305             buf.as_mut_ptr()
1306         );
1307         Ok(())
1308     }
1309 
1310     /// Copy elements of the java long array from the `start` index to the
1311     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1312     ///
1313     /// # Errors
1314     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1315     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1316     /// and `Err` is returned.
1317     ///
1318     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_long_array_region( &self, array: jlongArray, start: jsize, buf: &mut [jlong], ) -> Result<()>1319     pub fn get_long_array_region(
1320         &self,
1321         array: jlongArray,
1322         start: jsize,
1323         buf: &mut [jlong],
1324     ) -> Result<()> {
1325         non_null!(array, "get_long_array_region array argument");
1326         jni_void_call!(
1327             self.internal,
1328             GetLongArrayRegion,
1329             array,
1330             start,
1331             buf.len() as jsize,
1332             buf.as_mut_ptr()
1333         );
1334         Ok(())
1335     }
1336 
1337     /// Copy elements of the java float array from the `start` index to the
1338     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1339     ///
1340     /// # Errors
1341     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1342     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1343     /// and `Err` is returned.
1344     ///
1345     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_float_array_region( &self, array: jfloatArray, start: jsize, buf: &mut [jfloat], ) -> Result<()>1346     pub fn get_float_array_region(
1347         &self,
1348         array: jfloatArray,
1349         start: jsize,
1350         buf: &mut [jfloat],
1351     ) -> Result<()> {
1352         non_null!(array, "get_float_array_region array argument");
1353         jni_void_call!(
1354             self.internal,
1355             GetFloatArrayRegion,
1356             array,
1357             start,
1358             buf.len() as jsize,
1359             buf.as_mut_ptr()
1360         );
1361         Ok(())
1362     }
1363 
1364     /// Copy elements of the java double array from the `start` index to the
1365     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1366     ///
1367     /// # Errors
1368     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1369     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1370     /// and `Err` is returned.
1371     ///
1372     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_double_array_region( &self, array: jdoubleArray, start: jsize, buf: &mut [jdouble], ) -> Result<()>1373     pub fn get_double_array_region(
1374         &self,
1375         array: jdoubleArray,
1376         start: jsize,
1377         buf: &mut [jdouble],
1378     ) -> Result<()> {
1379         non_null!(array, "get_double_array_region array argument");
1380         jni_void_call!(
1381             self.internal,
1382             GetDoubleArrayRegion,
1383             array,
1384             start,
1385             buf.len() as jsize,
1386             buf.as_mut_ptr()
1387         );
1388         Ok(())
1389     }
1390 
1391     /// Copy the contents of the `buf` slice to the java boolean array at the
1392     /// `start` index.
set_boolean_array_region( &self, array: jbooleanArray, start: jsize, buf: &[jboolean], ) -> Result<()>1393     pub fn set_boolean_array_region(
1394         &self,
1395         array: jbooleanArray,
1396         start: jsize,
1397         buf: &[jboolean],
1398     ) -> Result<()> {
1399         non_null!(array, "set_boolean_array_region array argument");
1400         jni_void_call!(
1401             self.internal,
1402             SetBooleanArrayRegion,
1403             array,
1404             start,
1405             buf.len() as jsize,
1406             buf.as_ptr()
1407         );
1408         Ok(())
1409     }
1410 
1411     /// Copy the contents of the `buf` slice to the java byte array at the
1412     /// `start` index.
set_byte_array_region( &self, array: jbyteArray, start: jsize, buf: &[jbyte], ) -> Result<()>1413     pub fn set_byte_array_region(
1414         &self,
1415         array: jbyteArray,
1416         start: jsize,
1417         buf: &[jbyte],
1418     ) -> Result<()> {
1419         non_null!(array, "set_byte_array_region array argument");
1420         jni_void_call!(
1421             self.internal,
1422             SetByteArrayRegion,
1423             array,
1424             start,
1425             buf.len() as jsize,
1426             buf.as_ptr()
1427         );
1428         Ok(())
1429     }
1430 
1431     /// Copy the contents of the `buf` slice to the java char array at the
1432     /// `start` index.
set_char_array_region( &self, array: jcharArray, start: jsize, buf: &[jchar], ) -> Result<()>1433     pub fn set_char_array_region(
1434         &self,
1435         array: jcharArray,
1436         start: jsize,
1437         buf: &[jchar],
1438     ) -> Result<()> {
1439         non_null!(array, "set_char_array_region array argument");
1440         jni_void_call!(
1441             self.internal,
1442             SetCharArrayRegion,
1443             array,
1444             start,
1445             buf.len() as jsize,
1446             buf.as_ptr()
1447         );
1448         Ok(())
1449     }
1450 
1451     /// Copy the contents of the `buf` slice to the java short array at the
1452     /// `start` index.
set_short_array_region( &self, array: jshortArray, start: jsize, buf: &[jshort], ) -> Result<()>1453     pub fn set_short_array_region(
1454         &self,
1455         array: jshortArray,
1456         start: jsize,
1457         buf: &[jshort],
1458     ) -> Result<()> {
1459         non_null!(array, "set_short_array_region array argument");
1460         jni_void_call!(
1461             self.internal,
1462             SetShortArrayRegion,
1463             array,
1464             start,
1465             buf.len() as jsize,
1466             buf.as_ptr()
1467         );
1468         Ok(())
1469     }
1470 
1471     /// Copy the contents of the `buf` slice to the java int array at the
1472     /// `start` index.
set_int_array_region(&self, array: jintArray, start: jsize, buf: &[jint]) -> Result<()>1473     pub fn set_int_array_region(&self, array: jintArray, start: jsize, buf: &[jint]) -> Result<()> {
1474         non_null!(array, "set_int_array_region array argument");
1475         jni_void_call!(
1476             self.internal,
1477             SetIntArrayRegion,
1478             array,
1479             start,
1480             buf.len() as jsize,
1481             buf.as_ptr()
1482         );
1483         Ok(())
1484     }
1485 
1486     /// Copy the contents of the `buf` slice to the java long array at the
1487     /// `start` index.
set_long_array_region( &self, array: jlongArray, start: jsize, buf: &[jlong], ) -> Result<()>1488     pub fn set_long_array_region(
1489         &self,
1490         array: jlongArray,
1491         start: jsize,
1492         buf: &[jlong],
1493     ) -> Result<()> {
1494         non_null!(array, "set_long_array_region array argument");
1495         jni_void_call!(
1496             self.internal,
1497             SetLongArrayRegion,
1498             array,
1499             start,
1500             buf.len() as jsize,
1501             buf.as_ptr()
1502         );
1503         Ok(())
1504     }
1505 
1506     /// Copy the contents of the `buf` slice to the java float array at the
1507     /// `start` index.
set_float_array_region( &self, array: jfloatArray, start: jsize, buf: &[jfloat], ) -> Result<()>1508     pub fn set_float_array_region(
1509         &self,
1510         array: jfloatArray,
1511         start: jsize,
1512         buf: &[jfloat],
1513     ) -> Result<()> {
1514         non_null!(array, "set_float_array_region array argument");
1515         jni_void_call!(
1516             self.internal,
1517             SetFloatArrayRegion,
1518             array,
1519             start,
1520             buf.len() as jsize,
1521             buf.as_ptr()
1522         );
1523         Ok(())
1524     }
1525 
1526     /// Copy the contents of the `buf` slice to the java double array at the
1527     /// `start` index.
set_double_array_region( &self, array: jdoubleArray, start: jsize, buf: &[jdouble], ) -> Result<()>1528     pub fn set_double_array_region(
1529         &self,
1530         array: jdoubleArray,
1531         start: jsize,
1532         buf: &[jdouble],
1533     ) -> Result<()> {
1534         non_null!(array, "set_double_array_region array argument");
1535         jni_void_call!(
1536             self.internal,
1537             SetDoubleArrayRegion,
1538             array,
1539             start,
1540             buf.len() as jsize,
1541             buf.as_ptr()
1542         );
1543         Ok(())
1544     }
1545 
1546     /// Get a field without checking the provided type against the actual field.
get_field_unchecked<'f, O, T>( &self, obj: O, field: T, ty: JavaType, ) -> Result<JValue<'a>> where O: Into<JObject<'a>>, T: Desc<'a, JFieldID<'f>>,1547     pub fn get_field_unchecked<'f, O, T>(
1548         &self,
1549         obj: O,
1550         field: T,
1551         ty: JavaType,
1552     ) -> Result<JValue<'a>>
1553     where
1554         O: Into<JObject<'a>>,
1555         T: Desc<'a, JFieldID<'f>>,
1556     {
1557         let obj = obj.into();
1558         non_null!(obj, "get_field_typed obj argument");
1559 
1560         let field = field.lookup(self)?.into_inner();
1561         let obj = obj.into_inner();
1562 
1563         // TODO clean this up
1564         Ok(match ty {
1565             JavaType::Object(_) | JavaType::Array(_) => {
1566                 let obj: JObject =
1567                     jni_non_void_call!(self.internal, GetObjectField, obj, field).into();
1568                 obj.into()
1569             }
1570             // JavaType::Object
1571             JavaType::Method(_) => unimplemented!(),
1572             JavaType::Primitive(p) => match p {
1573                 Primitive::Boolean => {
1574                     jni_unchecked!(self.internal, GetBooleanField, obj, field).into()
1575                 }
1576                 Primitive::Char => jni_unchecked!(self.internal, GetCharField, obj, field).into(),
1577                 Primitive::Short => jni_unchecked!(self.internal, GetShortField, obj, field).into(),
1578                 Primitive::Int => jni_unchecked!(self.internal, GetIntField, obj, field).into(),
1579                 Primitive::Long => jni_unchecked!(self.internal, GetLongField, obj, field).into(),
1580                 Primitive::Float => jni_unchecked!(self.internal, GetFloatField, obj, field).into(),
1581                 Primitive::Double => {
1582                     jni_unchecked!(self.internal, GetDoubleField, obj, field).into()
1583                 }
1584                 Primitive::Byte => jni_unchecked!(self.internal, GetByteField, obj, field).into(),
1585                 Primitive::Void => {
1586                     return Err(Error::WrongJValueType("void", "see java field"));
1587                 }
1588             },
1589         })
1590     }
1591 
1592     /// Set a field without any type checking.
set_field_unchecked<'f, O, T>(&self, obj: O, field: T, val: JValue) -> Result<()> where O: Into<JObject<'a>>, T: Desc<'a, JFieldID<'f>>,1593     pub fn set_field_unchecked<'f, O, T>(&self, obj: O, field: T, val: JValue) -> Result<()>
1594     where
1595         O: Into<JObject<'a>>,
1596         T: Desc<'a, JFieldID<'f>>,
1597     {
1598         let obj = obj.into();
1599         non_null!(obj, "set_field_typed obj argument");
1600 
1601         let field = field.lookup(self)?.into_inner();
1602         let obj = obj.into_inner();
1603 
1604         // TODO clean this up
1605         match val {
1606             JValue::Object(o) => {
1607                 jni_unchecked!(self.internal, SetObjectField, obj, field, o.into_inner());
1608             }
1609             // JavaType::Object
1610             JValue::Bool(b) => {
1611                 jni_unchecked!(self.internal, SetBooleanField, obj, field, b);
1612             }
1613             JValue::Char(c) => {
1614                 jni_unchecked!(self.internal, SetCharField, obj, field, c);
1615             }
1616             JValue::Short(s) => {
1617                 jni_unchecked!(self.internal, SetShortField, obj, field, s);
1618             }
1619             JValue::Int(i) => {
1620                 jni_unchecked!(self.internal, SetIntField, obj, field, i);
1621             }
1622             JValue::Long(l) => {
1623                 jni_unchecked!(self.internal, SetLongField, obj, field, l);
1624             }
1625             JValue::Float(f) => {
1626                 jni_unchecked!(self.internal, SetFloatField, obj, field, f);
1627             }
1628             JValue::Double(d) => {
1629                 jni_unchecked!(self.internal, SetDoubleField, obj, field, d);
1630             }
1631             JValue::Byte(b) => {
1632                 jni_unchecked!(self.internal, SetByteField, obj, field, b);
1633             }
1634             JValue::Void => {
1635                 return Err(Error::WrongJValueType("void", "see java field"));
1636             }
1637         };
1638 
1639         Ok(())
1640     }
1641 
1642     /// Get a field. Requires an object class lookup and a field id lookup
1643     /// internally.
get_field<O, S, T>(&self, obj: O, name: S, ty: T) -> Result<JValue<'a>> where O: Into<JObject<'a>>, S: Into<JNIString>, T: Into<JNIString> + AsRef<str>,1644     pub fn get_field<O, S, T>(&self, obj: O, name: S, ty: T) -> Result<JValue<'a>>
1645     where
1646         O: Into<JObject<'a>>,
1647         S: Into<JNIString>,
1648         T: Into<JNIString> + AsRef<str>,
1649     {
1650         let obj = obj.into();
1651         let class = self.auto_local(self.get_object_class(obj)?);
1652 
1653         let parsed = JavaType::from_str(ty.as_ref())?;
1654 
1655         let field_id: JFieldID = (&class, name, ty).lookup(self)?;
1656 
1657         self.get_field_unchecked(obj, field_id, parsed)
1658     }
1659 
1660     /// Set a field. Does the same lookups as `get_field` and ensures that the
1661     /// type matches the given value.
set_field<O, S, T>(&self, obj: O, name: S, ty: T, val: JValue) -> Result<()> where O: Into<JObject<'a>>, S: Into<JNIString>, T: Into<JNIString> + AsRef<str>,1662     pub fn set_field<O, S, T>(&self, obj: O, name: S, ty: T, val: JValue) -> Result<()>
1663     where
1664         O: Into<JObject<'a>>,
1665         S: Into<JNIString>,
1666         T: Into<JNIString> + AsRef<str>,
1667     {
1668         let obj = obj.into();
1669         let parsed = JavaType::from_str(ty.as_ref())?;
1670         let in_type = val.primitive_type();
1671 
1672         match parsed {
1673             JavaType::Object(_) | JavaType::Array(_) => {
1674                 if in_type.is_some() {
1675                     return Err(Error::WrongJValueType(val.type_name(), "see java field"));
1676                 }
1677             }
1678             JavaType::Primitive(p) => {
1679                 if let Some(in_p) = in_type {
1680                     if in_p == p {
1681                         // good
1682                     } else {
1683                         return Err(Error::WrongJValueType(val.type_name(), "see java field"));
1684                     }
1685                 } else {
1686                     return Err(Error::WrongJValueType(val.type_name(), "see java field"));
1687                 }
1688             }
1689             JavaType::Method(_) => unimplemented!(),
1690         }
1691 
1692         let class = self.auto_local(self.get_object_class(obj)?);
1693 
1694         self.set_field_unchecked(obj, (&class, name, ty), val)
1695     }
1696 
1697     /// Get a static field without checking the provided type against the actual
1698     /// field.
get_static_field_unchecked<'c, 'f, T, U>( &self, class: T, field: U, ty: JavaType, ) -> Result<JValue<'a>> where T: Desc<'a, JClass<'c>>, U: Desc<'a, JStaticFieldID<'f>>,1699     pub fn get_static_field_unchecked<'c, 'f, T, U>(
1700         &self,
1701         class: T,
1702         field: U,
1703         ty: JavaType,
1704     ) -> Result<JValue<'a>>
1705     where
1706         T: Desc<'a, JClass<'c>>,
1707         U: Desc<'a, JStaticFieldID<'f>>,
1708     {
1709         use JavaType::Primitive as JP;
1710 
1711         let class = class.lookup(self)?.into_inner();
1712         let field = field.lookup(self)?.into_inner();
1713 
1714         let result = match ty {
1715             JavaType::Object(_) | JavaType::Array(_) => {
1716                 jni_non_void_call!(self.internal, GetStaticObjectField, class, field).into()
1717             }
1718             JavaType::Method(_) => return Err(Error::WrongJValueType("Method", "see java field")),
1719             JP(Primitive::Boolean) => {
1720                 jni_unchecked!(self.internal, GetStaticBooleanField, class, field).into()
1721             }
1722             JP(Primitive::Char) => {
1723                 jni_unchecked!(self.internal, GetStaticCharField, class, field).into()
1724             }
1725             JP(Primitive::Short) => {
1726                 jni_unchecked!(self.internal, GetStaticShortField, class, field).into()
1727             }
1728             JP(Primitive::Int) => {
1729                 jni_unchecked!(self.internal, GetStaticIntField, class, field).into()
1730             }
1731             JP(Primitive::Long) => {
1732                 jni_unchecked!(self.internal, GetStaticLongField, class, field).into()
1733             }
1734             JP(Primitive::Float) => {
1735                 jni_unchecked!(self.internal, GetStaticFloatField, class, field).into()
1736             }
1737             JP(Primitive::Double) => {
1738                 jni_unchecked!(self.internal, GetStaticDoubleField, class, field).into()
1739             }
1740             JP(Primitive::Byte) => {
1741                 jni_unchecked!(self.internal, GetStaticByteField, class, field).into()
1742             }
1743             JP(Primitive::Void) => return Err(Error::WrongJValueType("void", "see java field")),
1744         };
1745         Ok(result)
1746     }
1747 
1748     /// Get a static field. Requires a class lookup and a field id lookup
1749     /// internally.
get_static_field<'c, T, U, V>(&self, class: T, field: U, sig: V) -> Result<JValue<'a>> where T: Desc<'a, JClass<'c>>, U: Into<JNIString>, V: Into<JNIString> + AsRef<str>,1750     pub fn get_static_field<'c, T, U, V>(&self, class: T, field: U, sig: V) -> Result<JValue<'a>>
1751     where
1752         T: Desc<'a, JClass<'c>>,
1753         U: Into<JNIString>,
1754         V: Into<JNIString> + AsRef<str>,
1755     {
1756         let ty = JavaType::from_str(sig.as_ref())?;
1757 
1758         // go ahead and look up the class since it's already Copy,
1759         // and we'll need that for the next call.
1760         let class = class.lookup(self)?;
1761 
1762         self.get_static_field_unchecked(class, (class, field, sig), ty)
1763     }
1764 
1765     /// Set a static field. Requires a class lookup and a field id lookup internally.
set_static_field<'c, 'f, T, U>(&self, class: T, field: U, value: JValue) -> Result<()> where T: Desc<'a, JClass<'c>>, U: Desc<'a, JStaticFieldID<'f>>,1766     pub fn set_static_field<'c, 'f, T, U>(&self, class: T, field: U, value: JValue) -> Result<()>
1767     where
1768         T: Desc<'a, JClass<'c>>,
1769         U: Desc<'a, JStaticFieldID<'f>>,
1770     {
1771         let class = class.lookup(self)?.into_inner();
1772         let field = field.lookup(self)?.into_inner();
1773 
1774         match value {
1775             JValue::Object(v) => jni_unchecked!(
1776                 self.internal,
1777                 SetStaticObjectField,
1778                 class,
1779                 field,
1780                 v.into_inner()
1781             ),
1782             JValue::Byte(v) => jni_unchecked!(self.internal, SetStaticByteField, class, field, v),
1783             JValue::Char(v) => jni_unchecked!(self.internal, SetStaticCharField, class, field, v),
1784             JValue::Short(v) => jni_unchecked!(self.internal, SetStaticShortField, class, field, v),
1785             JValue::Int(v) => jni_unchecked!(self.internal, SetStaticIntField, class, field, v),
1786             JValue::Long(v) => jni_unchecked!(self.internal, SetStaticLongField, class, field, v),
1787             JValue::Bool(v) => {
1788                 jni_unchecked!(self.internal, SetStaticBooleanField, class, field, v)
1789             }
1790             JValue::Float(v) => jni_unchecked!(self.internal, SetStaticFloatField, class, field, v),
1791             JValue::Double(v) => {
1792                 jni_unchecked!(self.internal, SetStaticDoubleField, class, field, v)
1793             }
1794             JValue::Void => return Err(Error::WrongJValueType("void", "?")),
1795         }
1796 
1797         Ok(())
1798     }
1799 
1800     /// Surrenders ownership of a rust object to Java. Requires an object with a
1801     /// `long` field to store the pointer. The Rust value will be wrapped in a
1802     /// Mutex since Java will be controlling where it'll be used thread-wise.
1803     /// Unsafe because it leaks memory if `take_rust_field` is never called (so
1804     /// be sure to make a finalizer).
1805     ///
1806     /// **DO NOT** make a copy of the object containing one of these fields. If
1807     /// you've set up a finalizer to pass it back to Rust upon being GC'd, it
1808     /// will point to invalid memory and will likely attempt to be deallocated
1809     /// again.
1810     #[allow(unused_variables)]
set_rust_field<O, S, T>(&self, obj: O, field: S, rust_object: T) -> Result<()> where O: Into<JObject<'a>>, S: AsRef<str>, T: Send + 'static,1811     pub fn set_rust_field<O, S, T>(&self, obj: O, field: S, rust_object: T) -> Result<()>
1812     where
1813         O: Into<JObject<'a>>,
1814         S: AsRef<str>,
1815         T: Send + 'static,
1816     {
1817         let obj = obj.into();
1818         let class = self.auto_local(self.get_object_class(obj)?);
1819         let field_id: JFieldID = (&class, &field, "J").lookup(self)?;
1820 
1821         let guard = self.lock_obj(obj)?;
1822 
1823         // Check to see if we've already set this value. If it's not null, that
1824         // means that we're going to leak memory if it gets overwritten.
1825         let field_ptr = self
1826             .get_field_unchecked(obj, field_id, JavaType::Primitive(Primitive::Long))?
1827             .j()? as *mut Mutex<T>;
1828         if !field_ptr.is_null() {
1829             return Err(Error::FieldAlreadySet(field.as_ref().to_owned()));
1830         }
1831 
1832         let mbox = Box::new(::std::sync::Mutex::new(rust_object));
1833         let ptr: *mut Mutex<T> = Box::into_raw(mbox);
1834 
1835         self.set_field_unchecked(obj, field_id, (ptr as crate::sys::jlong).into())
1836     }
1837 
1838     /// Gets a lock on a Rust value that's been given to a Java object. Java
1839     /// still retains ownership and `take_rust_field` will still need to be
1840     /// called at some point. Checks for a null pointer, but assumes that the
1841     /// data it points to is valid for T.
1842     #[allow(unused_variables)]
get_rust_field<O, S, T>(&self, obj: O, field: S) -> Result<MutexGuard<T>> where O: Into<JObject<'a>>, S: Into<JNIString>, T: Send + 'static,1843     pub fn get_rust_field<O, S, T>(&self, obj: O, field: S) -> Result<MutexGuard<T>>
1844     where
1845         O: Into<JObject<'a>>,
1846         S: Into<JNIString>,
1847         T: Send + 'static,
1848     {
1849         let obj = obj.into();
1850         let guard = self.lock_obj(obj)?;
1851 
1852         let ptr = self.get_field(obj, field, "J")?.j()? as *mut Mutex<T>;
1853         non_null!(ptr, "rust value from Java");
1854         unsafe {
1855             // dereferencing is safe, because we checked it for null
1856             Ok((*ptr).lock().unwrap())
1857         }
1858     }
1859 
1860     /// Take a Rust field back from Java. Makes sure that the pointer is
1861     /// non-null, but still assumes that the data it points to is valid for T.
1862     /// Sets the field to a null pointer to signal that it's empty.
1863     ///
1864     /// This will return an error in the event that there's an outstanding lock
1865     /// on the object.
1866     #[allow(unused_variables)]
take_rust_field<O, S, T>(&self, obj: O, field: S) -> Result<T> where O: Into<JObject<'a>>, S: AsRef<str>, T: Send + 'static,1867     pub fn take_rust_field<O, S, T>(&self, obj: O, field: S) -> Result<T>
1868     where
1869         O: Into<JObject<'a>>,
1870         S: AsRef<str>,
1871         T: Send + 'static,
1872     {
1873         let obj = obj.into();
1874         let class = self.auto_local(self.get_object_class(obj)?);
1875         let field_id: JFieldID = (&class, &field, "J").lookup(self)?;
1876 
1877         let mbox = {
1878             let guard = self.lock_obj(obj)?;
1879 
1880             let ptr = self
1881                 .get_field_unchecked(obj, field_id, JavaType::Primitive(Primitive::Long))?
1882                 .j()? as *mut Mutex<T>;
1883 
1884             non_null!(ptr, "rust value from Java");
1885 
1886             let mbox = unsafe { Box::from_raw(ptr) };
1887 
1888             // attempt to acquire the lock. This prevents us from consuming the
1889             // mutex if there's an outstanding lock. No one else will be able to
1890             // get a new one as long as we're in the guarded scope.
1891             drop(mbox.try_lock()?);
1892 
1893             self.set_field_unchecked(
1894                 obj,
1895                 field_id,
1896                 (::std::ptr::null_mut::<()>() as sys::jlong).into(),
1897             )?;
1898 
1899             mbox
1900         };
1901 
1902         Ok(mbox.into_inner().unwrap())
1903     }
1904 
1905     /// Lock a Java object. The MonitorGuard that this returns is responsible
1906     /// for ensuring that it gets unlocked.
lock_obj<O>(&self, obj: O) -> Result<MonitorGuard<'a>> where O: Into<JObject<'a>>,1907     pub fn lock_obj<O>(&self, obj: O) -> Result<MonitorGuard<'a>>
1908     where
1909         O: Into<JObject<'a>>,
1910     {
1911         let inner = obj.into().into_inner();
1912         let _ = jni_unchecked!(self.internal, MonitorEnter, inner);
1913 
1914         Ok(MonitorGuard {
1915             obj: inner,
1916             env: self.internal,
1917             life: Default::default(),
1918         })
1919     }
1920 
1921     /// Returns underlying `sys::JNIEnv` interface.
get_native_interface(&self) -> *mut sys::JNIEnv1922     pub fn get_native_interface(&self) -> *mut sys::JNIEnv {
1923         self.internal
1924     }
1925 
1926     /// Returns the Java VM interface.
get_java_vm(&self) -> Result<JavaVM>1927     pub fn get_java_vm(&self) -> Result<JavaVM> {
1928         let mut raw = ptr::null_mut();
1929         let res = jni_unchecked!(self.internal, GetJavaVM, &mut raw);
1930         jni_error_code_to_result(res)?;
1931         unsafe { JavaVM::from_raw(raw) }
1932     }
1933 
1934     /// Ensures that at least a given number of local references can be created
1935     /// in the current thread.
ensure_local_capacity(&self, capacity: jint) -> Result<()>1936     pub fn ensure_local_capacity(&self, capacity: jint) -> Result<()> {
1937         jni_void_call!(self.internal, EnsureLocalCapacity, capacity);
1938         Ok(())
1939     }
1940 
1941     /// Bind function pointers to native methods of class
1942     /// according to method name and signature.
1943     /// For details see [documentation](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#RegisterNatives).
register_native_methods<'c, T>(&self, class: T, methods: &[NativeMethod]) -> Result<()> where T: Desc<'a, JClass<'c>>,1944     pub fn register_native_methods<'c, T>(&self, class: T, methods: &[NativeMethod]) -> Result<()>
1945     where
1946         T: Desc<'a, JClass<'c>>,
1947     {
1948         let class = class.lookup(self)?;
1949         let jni_native_methods: Vec<JNINativeMethod> = methods
1950             .iter()
1951             .map(|nm| JNINativeMethod {
1952                 name: nm.name.as_ptr() as *mut c_char,
1953                 signature: nm.sig.as_ptr() as *mut c_char,
1954                 fnPtr: nm.fn_ptr,
1955             })
1956             .collect();
1957         let res = jni_non_void_call!(
1958             self.internal,
1959             RegisterNatives,
1960             class.into_inner(),
1961             jni_native_methods.as_ptr(),
1962             jni_native_methods.len() as jint
1963         );
1964         jni_error_code_to_result(res)
1965     }
1966 
1967     /// Unbind all native methods of class.
unregister_native_methods<'c, T>(&self, class: T) -> Result<()> where T: Desc<'a, JClass<'c>>,1968     pub fn unregister_native_methods<'c, T>(&self, class: T) -> Result<()>
1969     where
1970         T: Desc<'a, JClass<'c>>,
1971     {
1972         let class = class.lookup(self)?;
1973         let res = jni_non_void_call!(self.internal, UnregisterNatives, class.into_inner());
1974         jni_error_code_to_result(res)
1975     }
1976 
1977     /// Return an AutoArray of the given Java array.
1978     ///
1979     /// The result is valid until the AutoArray object goes out of scope, when the
1980     /// release happens automatically according to the mode parameter.
1981     ///
1982     /// Since the returned array may be a copy of the Java array, changes made to the
1983     /// returned array will not necessarily be reflected in the original array until
1984     /// the corresponding Release*ArrayElements JNI method is called.
1985     /// AutoArray has a commit() method, to force a copy of the array if needed (and without
1986     /// releasing it).
1987 
1988     /// Prefer to use the convenience wrappers:
1989     /// [`get_int_array_elements`](struct.JNIEnv.html#method.get_int_array_elements)
1990     /// [`get_long_array_elements`](struct.JNIEnv.html#method.get_long_array_elements)
1991     /// [`get_byte_array_elements`](struct.JNIEnv.html#method.get_byte_array_elements)
1992     /// [`get_boolean_array_elements`](struct.JNIEnv.html#method.get_boolean_array_elements)
1993     /// [`get_char_array_elements`](struct.JNIEnv.html#method.get_char_array_elements)
1994     /// [`get_short_array_elements`](struct.JNIEnv.html#method.get_short_array_elements)
1995     /// [`get_float_array_elements`](struct.JNIEnv.html#method.get_float_array_elements)
1996     /// [`get_double_array_elements`](struct.JNIEnv.html#method.get_double_array_elements)
1997     /// And the associated [`AutoArray`](struct.objects.AutoArray) struct.
get_array_elements<T: TypeArray>( &self, array: jarray, mode: ReleaseMode, ) -> Result<AutoArray<T>>1998     pub fn get_array_elements<T: TypeArray>(
1999         &self,
2000         array: jarray,
2001         mode: ReleaseMode,
2002     ) -> Result<AutoArray<T>> {
2003         non_null!(array, "get_array_elements array argument");
2004         AutoArray::new(self, array.into(), mode)
2005     }
2006 
2007     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_int_array_elements( &self, array: jintArray, mode: ReleaseMode, ) -> Result<AutoArray<jint>>2008     pub fn get_int_array_elements(
2009         &self,
2010         array: jintArray,
2011         mode: ReleaseMode,
2012     ) -> Result<AutoArray<jint>> {
2013         self.get_array_elements(array, mode)
2014     }
2015 
2016     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_long_array_elements( &self, array: jlongArray, mode: ReleaseMode, ) -> Result<AutoArray<jlong>>2017     pub fn get_long_array_elements(
2018         &self,
2019         array: jlongArray,
2020         mode: ReleaseMode,
2021     ) -> Result<AutoArray<jlong>> {
2022         self.get_array_elements(array, mode)
2023     }
2024 
2025     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_byte_array_elements( &self, array: jbyteArray, mode: ReleaseMode, ) -> Result<AutoArray<jbyte>>2026     pub fn get_byte_array_elements(
2027         &self,
2028         array: jbyteArray,
2029         mode: ReleaseMode,
2030     ) -> Result<AutoArray<jbyte>> {
2031         self.get_array_elements(array, mode)
2032     }
2033 
2034     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_boolean_array_elements( &self, array: jbooleanArray, mode: ReleaseMode, ) -> Result<AutoArray<jboolean>>2035     pub fn get_boolean_array_elements(
2036         &self,
2037         array: jbooleanArray,
2038         mode: ReleaseMode,
2039     ) -> Result<AutoArray<jboolean>> {
2040         self.get_array_elements(array, mode)
2041     }
2042 
2043     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_char_array_elements( &self, array: jcharArray, mode: ReleaseMode, ) -> Result<AutoArray<jchar>>2044     pub fn get_char_array_elements(
2045         &self,
2046         array: jcharArray,
2047         mode: ReleaseMode,
2048     ) -> Result<AutoArray<jchar>> {
2049         self.get_array_elements(array, mode)
2050     }
2051 
2052     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_short_array_elements( &self, array: jshortArray, mode: ReleaseMode, ) -> Result<AutoArray<jshort>>2053     pub fn get_short_array_elements(
2054         &self,
2055         array: jshortArray,
2056         mode: ReleaseMode,
2057     ) -> Result<AutoArray<jshort>> {
2058         self.get_array_elements(array, mode)
2059     }
2060 
2061     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_float_array_elements( &self, array: jfloatArray, mode: ReleaseMode, ) -> Result<AutoArray<jfloat>>2062     pub fn get_float_array_elements(
2063         &self,
2064         array: jfloatArray,
2065         mode: ReleaseMode,
2066     ) -> Result<AutoArray<jfloat>> {
2067         self.get_array_elements(array, mode)
2068     }
2069 
2070     /// See also [`get_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_double_array_elements( &self, array: jdoubleArray, mode: ReleaseMode, ) -> Result<AutoArray<jdouble>>2071     pub fn get_double_array_elements(
2072         &self,
2073         array: jdoubleArray,
2074         mode: ReleaseMode,
2075     ) -> Result<AutoArray<jdouble>> {
2076         self.get_array_elements(array, mode)
2077     }
2078 
2079     /// Return an AutoPrimitiveArray of the given Java primitive array.
2080     ///
2081     /// The result is valid until the corresponding AutoPrimitiveArray object goes out of scope,
2082     /// when the release happens automatically according to the mode parameter.
2083     ///
2084     /// Given that Critical sections must be as short as possible, and that they come with a
2085     /// number of important restrictions (see GetPrimitiveArrayCritical JNI doc), use this
2086     /// wrapper wisely, to avoid holding the array longer that strictly necessary.
2087     /// In any case, you can:
2088     ///  - Use std::mem::drop explicitly, to force / anticipate resource release.
2089     ///  - Use a nested scope, to release the array at the nested scope's exit.
2090     ///
2091     /// Since the returned array may be a copy of the Java array, changes made to the
2092     /// returned array will not necessarily be reflected in the original array until
2093     /// ReleasePrimitiveArrayCritical is called; which happens at AutoPrimitiveArray
2094     /// destruction.
2095     ///
2096     /// If the given array is `null`, an `Error::NullPtr` is returned.
2097     ///
2098     /// See also [`get_byte_array_elements`](struct.JNIEnv.html#method.get_array_elements)
get_primitive_array_critical( &self, array: jarray, mode: ReleaseMode, ) -> Result<AutoPrimitiveArray>2099     pub fn get_primitive_array_critical(
2100         &self,
2101         array: jarray,
2102         mode: ReleaseMode,
2103     ) -> Result<AutoPrimitiveArray> {
2104         non_null!(array, "get_primitive_array_critical array argument");
2105         let mut is_copy: jboolean = 0xff;
2106         // Even though this method may throw OoME, use `jni_unchecked`
2107         // instead of `jni_non_null_call` to remove (a slight) overhead
2108         // of exception checking. An error will still be detected as a `null`
2109         // result inside AutoPrimitiveArray ctor; and, as this method is unlikely
2110         // to create a copy, an OoME is highly unlikely.
2111         let ptr = jni_unchecked!(
2112             self.internal,
2113             GetPrimitiveArrayCritical,
2114             array,
2115             &mut is_copy
2116         );
2117         AutoPrimitiveArray::new(self, array.into(), ptr, mode, is_copy == sys::JNI_TRUE)
2118     }
2119 }
2120 
2121 /// Native method descriptor.
2122 pub struct NativeMethod {
2123     /// Name of method.
2124     pub name: JNIString,
2125     /// Method signature.
2126     pub sig: JNIString,
2127     /// Pointer to native function with signature
2128     /// `fn(env: JNIEnv, class: JClass, ...arguments according to sig) -> RetType`
2129     /// for static methods or
2130     /// `fn(env: JNIEnv, object: JObject, ...arguments according to sig) -> RetType`
2131     /// for instance methods.
2132     pub fn_ptr: *mut c_void,
2133 }
2134 
2135 /// Guard for a lock on a java object. This gets returned from the `lock_obj`
2136 /// method.
2137 pub struct MonitorGuard<'a> {
2138     obj: sys::jobject,
2139     env: *mut sys::JNIEnv,
2140     life: PhantomData<&'a ()>,
2141 }
2142 
2143 impl<'a> Drop for MonitorGuard<'a> {
drop(&mut self)2144     fn drop(&mut self) {
2145         let res: Result<()> = catch!({
2146             jni_unchecked!(self.env, MonitorExit, self.obj);
2147             Ok(())
2148         });
2149 
2150         if let Err(e) = res {
2151             warn!("error releasing java monitor: {}", e)
2152         }
2153     }
2154 }
2155