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