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::{
12     descriptors::Desc,
13     errors::*,
14     objects::{
15         AutoElements, AutoElementsCritical, AutoLocal, GlobalRef, JByteBuffer, JClass, JFieldID,
16         JList, JMap, JMethodID, JObject, JStaticFieldID, JStaticMethodID, JString, JThrowable,
17         JValue, JValueOwned, ReleaseMode, TypeArray, WeakRef,
18     },
19     signature::{JavaType, Primitive, TypeSignature},
20     strings::{JNIString, JavaStr},
21     sys::{
22         self, jarray, jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort, jsize, jvalue,
23         JNINativeMethod,
24     },
25     JNIVersion, JavaVM,
26 };
27 use crate::{
28     errors::Error::JniCall,
29     objects::{
30         JBooleanArray, JByteArray, JCharArray, JDoubleArray, JFloatArray, JIntArray, JLongArray,
31         JObjectArray, JPrimitiveArray, JShortArray,
32     },
33 };
34 use crate::{objects::AsJArrayRaw, signature::ReturnType};
35 
36 /// FFI-compatible JNIEnv struct. You can safely use this as the JNIEnv argument
37 /// to exported methods that will be called by java. This is where most of the
38 /// magic happens. All methods on this object are wrappers around JNI functions,
39 /// so the documentation on their behavior is still pretty applicable.
40 ///
41 /// # Exception handling
42 ///
43 /// Since we're calling into the JVM with this, many methods also have the
44 /// potential to cause an exception to get thrown. If this is the case, an `Err`
45 /// result will be returned with the error kind `JavaException`. Note that this
46 /// will _not_ clear the exception - it's up to the caller to decide whether to
47 /// do so or to let it continue being thrown.
48 ///
49 /// # References and Lifetimes
50 ///
51 /// As in C JNI, interactions with Java objects happen through <dfn>references</dfn>, either local
52 /// or global, represented by [`JObject`] and [`GlobalRef`] respectively. So long as there is at
53 /// least one such reference to a Java object, the JVM garbage collector will not reclaim it.
54 ///
55 /// <dfn>Global references</dfn> exist until deleted. Deletion occurs when the `GlobalRef` is
56 /// dropped.
57 ///
58 /// <dfn>Local references</dfn> belong to a local reference frame, and exist until
59 /// [deleted][JNIEnv::delete_local_ref] or until the local reference frame is exited. A <dfn>local
60 /// reference frame</dfn> is entered when a native method is called from Java, or when Rust code
61 /// does so explicitly using [`JNIEnv::with_local_frame`]. That local reference frame is exited
62 /// when the native method or `with_local_frame` returns. When a local reference frame is exited,
63 /// all local references created inside it are deleted.
64 ///
65 /// Unlike C JNI, this crate creates a separate `JNIEnv` for each local reference frame. The
66 /// associated Rust lifetime `'local` represents that local reference frame. Rust's borrow checker
67 /// will ensure that local references are not used after their local reference frame exits (which
68 /// would cause undefined behavior).
69 ///
70 /// Unlike global references, local references are not deleted when dropped by default. This is for
71 /// performance: it is faster for the JVM to delete all of the local references in a frame all at
72 /// once, than to delete each local reference one at a time. However, this can cause a memory leak
73 /// if the local reference frame remains entered for a long time, such as a long-lasting loop, in
74 /// which case local references should be deleted explicitly. Local references can be deleted when
75 /// dropped if desired; use [`JNIEnv::auto_local`] to arrange that.
76 ///
77 /// ## Lifetime Names
78 ///
79 /// This crate uses the following convention for lifetime names:
80 ///
81 /// * `'local` is the lifetime of a local reference frame, as described above.
82 ///
83 /// * `'other_local`, `'other_local_1`, and `'other_local_2` are the lifetimes of some other local
84 ///   reference frame, which may be but doesn't have to be the same as `'local`. For example,
85 ///   [`JNIEnv::new_local_ref`] accepts a local reference in any local reference frame
86 ///   `'other_local` and creates a new local reference to the same object in `'local`.
87 ///
88 /// * `'obj_ref` is the lifetime of a borrow of a JNI reference, like <code>&amp;[JObject]</code>
89 ///   or <code>&amp;[GlobalRef]</code>. For example, [`JNIEnv::get_list`] constructs a new
90 ///   [`JList`] that borrows a `&'obj_ref JObject`.
91 ///
92 /// ## `null` Java references
93 /// `null` Java references are handled by the following rules:
94 ///   - If a `null` Java reference is passed to a method that expects a non-`null`
95 ///   argument, an `Err` result with the kind `NullPtr` is returned.
96 ///   - If a JNI function returns `null` to indicate an error (e.g. `new_int_array`),
97 ///     it is converted to `Err`/`NullPtr` or, where possible, to a more applicable
98 ///     error type, such as `MethodNotFound`. If the JNI function also throws
99 ///     an exception, the `JavaException` error kind will be preferred.
100 ///   - If a JNI function may return `null` Java reference as one of possible reference
101 ///     values (e.g., `get_object_array_element` or `get_field_unchecked`),
102 ///     it is converted to `JObject::null()`.
103 ///
104 /// # `&self` and `&mut self`
105 ///
106 /// Most of the methods on this type take a `&mut self` reference, specifically all methods that
107 /// can enter a new local reference frame. This includes anything that might invoke user-defined
108 /// Java code, which can indirectly enter a new local reference frame by calling a native method.
109 ///
110 /// The reason for this restriction is to ensure that a `JNIEnv` instance can only be used in the
111 /// local reference frame that it belongs to. This, in turn, ensures that it is not possible to
112 /// create [`JObject`]s with the lifetime of a different local reference frame, which would lead to
113 /// undefined behavior. (See [issue #392] for background discussion.)
114 ///
115 /// [issue #392]: https://github.com/jni-rs/jni-rs/issues/392
116 ///
117 /// ## `cannot borrow as mutable`
118 ///
119 /// If a function takes two or more parameters, one of them is `JNIEnv`, and another is something
120 /// returned by a `JNIEnv` method (like [`JObject`]), then calls to that function may not compile:
121 ///
122 /// ```rust,compile_fail
123 /// # use jni::{errors::Result, JNIEnv, objects::*};
124 /// #
125 /// # fn f(env: &mut JNIEnv) -> Result<()> {
126 /// fn example_function(
127 ///     env: &mut JNIEnv,
128 ///     obj: &JObject,
129 /// ) {
130 ///     // …
131 /// }
132 ///
133 /// example_function(
134 ///     env,
135 ///     // ERROR: cannot borrow `*env` as mutable more than once at a time
136 ///     &env.new_object(
137 ///         "com/example/SomeClass",
138 ///         "()V",
139 ///         &[],
140 ///     )?,
141 /// )
142 /// # ; Ok(())
143 /// # }
144 /// ```
145 ///
146 /// To fix this, the `JNIEnv` parameter needs to come *last*:
147 ///
148 /// ```rust,no_run
149 /// # use jni::{errors::Result, JNIEnv, objects::*};
150 /// #
151 /// # fn f(env: &mut JNIEnv) -> Result<()> {
152 /// fn example_function(
153 ///     obj: &JObject,
154 ///     env: &mut JNIEnv,
155 /// ) {
156 ///     // …
157 /// }
158 ///
159 /// example_function(
160 ///     &env.new_object(
161 ///         "com/example/SomeClass",
162 ///         "()V",
163 ///         &[],
164 ///     )?,
165 ///     env,
166 /// )
167 /// # ; Ok(())
168 /// # }
169 /// ```
170 ///
171 /// # Checked and unchecked methods
172 ///
173 /// Some of the methods come in two versions: checked (e.g. `call_method`) and
174 /// unchecked (e.g. `call_method_unchecked`). Under the hood, checked methods
175 /// perform some checks to ensure the validity of provided signatures, names
176 /// and arguments, and then call the corresponding unchecked method.
177 ///
178 /// Checked methods are more flexible as they allow passing class names
179 /// and method/field descriptors as strings and may perform lookups
180 /// of class objects and method/field ids for you, also performing
181 /// all the needed precondition checks. However, these lookup operations
182 /// are expensive, so if you need to call the same method (or access
183 /// the same field) multiple times, it is
184 /// [recommended](https://docs.oracle.com/en/java/javase/11/docs/specs/jni/design.html#accessing-fields-and-methods)
185 /// to cache the instance of the class and the method/field id, e.g.
186 ///   - in loops
187 ///   - when calling the same Java callback repeatedly.
188 ///
189 /// If you do not cache references to classes and method/field ids,
190 /// you will *not* benefit from the unchecked methods.
191 ///
192 /// Calling unchecked methods with invalid arguments and/or invalid class and
193 /// method descriptors may lead to segmentation fault.
194 #[repr(transparent)]
195 #[derive(Debug)]
196 pub struct JNIEnv<'local> {
197     internal: *mut sys::JNIEnv,
198     lifetime: PhantomData<&'local ()>,
199 }
200 
201 impl<'local> JNIEnv<'local> {
202     /// Create a JNIEnv from a raw pointer.
203     ///
204     /// # Safety
205     ///
206     /// Expects a valid pointer retrieved from the `GetEnv` JNI function or [Self::get_raw] function. Only does a null check.
from_raw(ptr: *mut sys::JNIEnv) -> Result<Self>207     pub unsafe fn from_raw(ptr: *mut sys::JNIEnv) -> Result<Self> {
208         non_null!(ptr, "from_raw ptr argument");
209         Ok(JNIEnv {
210             internal: ptr,
211             lifetime: PhantomData,
212         })
213     }
214 
215     /// Get the raw JNIEnv pointer
get_raw(&self) -> *mut sys::JNIEnv216     pub fn get_raw(&self) -> *mut sys::JNIEnv {
217         self.internal
218     }
219 
220     /// Duplicates this `JNIEnv`.
221     ///
222     /// # Safety
223     ///
224     /// The duplicate `JNIEnv` must not be used to create any local references, unless they are
225     /// discarded before the current [local reference frame] is exited. Otherwise, they may have a
226     /// lifetime longer than they are actually valid for, resulting in a use-after-free bug and
227     /// undefined behavior.
228     ///
229     /// See [issue #392] for background.
230     ///
231     /// [local reference frame]: JNIEnv::with_local_frame
232     /// [issue #392]: https://github.com/jni-rs/jni-rs/issues/392
unsafe_clone(&self) -> Self233     pub unsafe fn unsafe_clone(&self) -> Self {
234         Self {
235             internal: self.internal,
236             lifetime: self.lifetime,
237         }
238     }
239 
240     /// Get the java version that we're being executed from.
get_version(&self) -> Result<JNIVersion>241     pub fn get_version(&self) -> Result<JNIVersion> {
242         Ok(jni_unchecked!(self.internal, GetVersion).into())
243     }
244 
245     /// Load a class from a buffer of raw class data. The name of the class must match the name
246     /// encoded within the class file data.
define_class<S>( &mut self, name: S, loader: &JObject, buf: &[u8], ) -> Result<JClass<'local>> where S: Into<JNIString>,247     pub fn define_class<S>(
248         &mut self,
249         name: S,
250         loader: &JObject,
251         buf: &[u8],
252     ) -> Result<JClass<'local>>
253     where
254         S: Into<JNIString>,
255     {
256         let name = name.into();
257         self.define_class_impl(name.as_ptr(), loader, buf)
258     }
259 
260     /// Load a class from a buffer of raw class data. The name of the class is inferred from the
261     /// buffer.
define_unnamed_class(&mut self, loader: &JObject, buf: &[u8]) -> Result<JClass<'local>>262     pub fn define_unnamed_class(&mut self, loader: &JObject, buf: &[u8]) -> Result<JClass<'local>> {
263         self.define_class_impl(ptr::null(), loader, buf)
264     }
265 
266     // Note: This requires `&mut` because it might invoke a method on a user-defined `ClassLoader`.
define_class_impl( &mut self, name: *const c_char, loader: &JObject, buf: &[u8], ) -> Result<JClass<'local>>267     fn define_class_impl(
268         &mut self,
269         name: *const c_char,
270         loader: &JObject,
271         buf: &[u8],
272     ) -> Result<JClass<'local>> {
273         let class = jni_non_null_call!(
274             self.internal,
275             DefineClass,
276             name,
277             loader.as_raw(),
278             buf.as_ptr() as *const jbyte,
279             buf.len() as jsize
280         );
281         Ok(unsafe { JClass::from_raw(class) })
282     }
283 
284     /// Load a class from a buffer of raw class data. The name of the class must match the name
285     /// encoded within the class file data.
define_class_bytearray<S>( &mut self, name: S, loader: &JObject, buf: &AutoElements<'_, '_, '_, jbyte>, ) -> Result<JClass<'local>> where S: Into<JNIString>,286     pub fn define_class_bytearray<S>(
287         &mut self,
288         name: S,
289         loader: &JObject,
290         buf: &AutoElements<'_, '_, '_, jbyte>,
291     ) -> Result<JClass<'local>>
292     where
293         S: Into<JNIString>,
294     {
295         let name = name.into();
296         let class = jni_non_null_call!(
297             self.internal,
298             DefineClass,
299             name.as_ptr(),
300             loader.as_raw(),
301             buf.as_ptr(),
302             buf.len() as _
303         );
304         Ok(unsafe { JClass::from_raw(class) })
305     }
306 
307     /// Look up a class by name.
308     ///
309     /// # Example
310     /// ```rust,no_run
311     /// # use jni::{errors::Result, JNIEnv, objects::JClass};
312     /// #
313     /// # fn example<'local>(env: &mut JNIEnv<'local>) -> Result<()> {
314     /// let class: JClass<'local> = env.find_class("java/lang/String")?;
315     /// # Ok(())
316     /// # }
317     /// ```
find_class<S>(&mut self, name: S) -> Result<JClass<'local>> where S: Into<JNIString>,318     pub fn find_class<S>(&mut self, name: S) -> Result<JClass<'local>>
319     where
320         S: Into<JNIString>,
321     {
322         let name = name.into();
323         let class = jni_non_null_call!(self.internal, FindClass, name.as_ptr());
324         Ok(unsafe { JClass::from_raw(class) })
325     }
326 
327     /// Returns the superclass for a particular class. Returns None for `java.lang.Object` or
328     /// an interface. As with [Self::find_class], takes a descriptor
329     ///
330     /// # Errors
331     ///
332     /// If a JNI call fails
get_superclass<'other_local, T>(&mut self, class: T) -> Result<Option<JClass<'local>>> where T: Desc<'local, JClass<'other_local>>,333     pub fn get_superclass<'other_local, T>(&mut self, class: T) -> Result<Option<JClass<'local>>>
334     where
335         T: Desc<'local, JClass<'other_local>>,
336     {
337         let class = class.lookup(self)?;
338         let superclass = unsafe {
339             JClass::from_raw(jni_unchecked!(
340                 self.internal,
341                 GetSuperclass,
342                 class.as_ref().as_raw()
343             ))
344         };
345 
346         Ok((!superclass.is_null()).then_some(superclass))
347     }
348 
349     /// Tests whether class1 is assignable from class2.
is_assignable_from<'other_local_1, 'other_local_2, T, U>( &mut self, class1: T, class2: U, ) -> Result<bool> where T: Desc<'local, JClass<'other_local_1>>, U: Desc<'local, JClass<'other_local_2>>,350     pub fn is_assignable_from<'other_local_1, 'other_local_2, T, U>(
351         &mut self,
352         class1: T,
353         class2: U,
354     ) -> Result<bool>
355     where
356         T: Desc<'local, JClass<'other_local_1>>,
357         U: Desc<'local, JClass<'other_local_2>>,
358     {
359         let class1 = class1.lookup(self)?;
360         let class2 = class2.lookup(self)?;
361         Ok(jni_unchecked!(
362             self.internal,
363             IsAssignableFrom,
364             class1.as_ref().as_raw(),
365             class2.as_ref().as_raw()
366         ) == sys::JNI_TRUE)
367     }
368 
369     /// Returns true if the object reference can be cast to the given type.
370     ///
371     /// _NB: Unlike the operator `instanceof`, function `IsInstanceOf` *returns `true`*
372     /// for all classes *if `object` is `null`.*_
373     ///
374     /// See [JNI documentation](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#IsInstanceOf)
375     /// for details.
is_instance_of<'other_local_1, 'other_local_2, O, T>( &mut self, object: O, class: T, ) -> Result<bool> where O: AsRef<JObject<'other_local_1>>, T: Desc<'local, JClass<'other_local_2>>,376     pub fn is_instance_of<'other_local_1, 'other_local_2, O, T>(
377         &mut self,
378         object: O,
379         class: T,
380     ) -> Result<bool>
381     where
382         O: AsRef<JObject<'other_local_1>>,
383         T: Desc<'local, JClass<'other_local_2>>,
384     {
385         let class = class.lookup(self)?;
386         Ok(jni_unchecked!(
387             self.internal,
388             IsInstanceOf,
389             object.as_ref().as_raw(),
390             class.as_ref().as_raw()
391         ) == sys::JNI_TRUE)
392     }
393 
394     /// Returns true if ref1 and ref2 refer to the same Java object, or are both `NULL`. Otherwise,
395     /// returns false.
is_same_object<'other_local_1, 'other_local_2, O, T>( &self, ref1: O, ref2: T, ) -> Result<bool> where O: AsRef<JObject<'other_local_1>>, T: AsRef<JObject<'other_local_2>>,396     pub fn is_same_object<'other_local_1, 'other_local_2, O, T>(
397         &self,
398         ref1: O,
399         ref2: T,
400     ) -> Result<bool>
401     where
402         O: AsRef<JObject<'other_local_1>>,
403         T: AsRef<JObject<'other_local_2>>,
404     {
405         Ok(jni_unchecked!(
406             self.internal,
407             IsSameObject,
408             ref1.as_ref().as_raw(),
409             ref2.as_ref().as_raw()
410         ) == sys::JNI_TRUE)
411     }
412 
413     /// Raise an exception from an existing object. This will continue being
414     /// thrown in java unless `exception_clear` is called.
415     ///
416     /// # Examples
417     /// ```rust,no_run
418     /// # use jni::{errors::Result, JNIEnv};
419     /// #
420     /// # fn example(env: &mut JNIEnv) -> Result<()> {
421     /// env.throw(("java/lang/Exception", "something bad happened"))?;
422     /// # Ok(())
423     /// # }
424     /// ```
425     ///
426     /// Defaulting to "java/lang/Exception":
427     ///
428     /// ```rust,no_run
429     /// # use jni::{errors::Result, JNIEnv};
430     /// #
431     /// # fn example(env: &mut JNIEnv) -> Result<()> {
432     /// env.throw("something bad happened")?;
433     /// # Ok(())
434     /// # }
435     /// ```
throw<'other_local, E>(&mut self, obj: E) -> Result<()> where E: Desc<'local, JThrowable<'other_local>>,436     pub fn throw<'other_local, E>(&mut self, obj: E) -> Result<()>
437     where
438         E: Desc<'local, JThrowable<'other_local>>,
439     {
440         let throwable = obj.lookup(self)?;
441         let res: i32 = jni_unchecked!(self.internal, Throw, throwable.as_ref().as_raw());
442 
443         // Ensure that `throwable` isn't dropped before the JNI call returns.
444         drop(throwable);
445 
446         if res == 0 {
447             Ok(())
448         } else {
449             Err(Error::ThrowFailed(res))
450         }
451     }
452 
453     /// Create and throw a new exception from a class descriptor and an error
454     /// message.
455     ///
456     /// # Example
457     /// ```rust,no_run
458     /// # use jni::{errors::Result, JNIEnv};
459     /// #
460     /// # fn example(env: &mut JNIEnv) -> Result<()> {
461     /// env.throw_new("java/lang/Exception", "something bad happened")?;
462     /// # Ok(())
463     /// # }
464     /// ```
throw_new<'other_local, S, T>(&mut self, class: T, msg: S) -> Result<()> where S: Into<JNIString>, T: Desc<'local, JClass<'other_local>>,465     pub fn throw_new<'other_local, S, T>(&mut self, class: T, msg: S) -> Result<()>
466     where
467         S: Into<JNIString>,
468         T: Desc<'local, JClass<'other_local>>,
469     {
470         let class = class.lookup(self)?;
471         let msg = msg.into();
472         let res: i32 = jni_unchecked!(
473             self.internal,
474             ThrowNew,
475             class.as_ref().as_raw(),
476             msg.as_ptr()
477         );
478 
479         // Ensure that `class` isn't dropped before the JNI call returns.
480         drop(class);
481 
482         if res == 0 {
483             Ok(())
484         } else {
485             Err(Error::ThrowFailed(res))
486         }
487     }
488 
489     /// Check whether or not an exception is currently in the process of being
490     /// thrown. An exception is in this state from the time it gets thrown and
491     /// not caught in a java function until `exception_clear` is called.
exception_occurred(&mut self) -> Result<JThrowable<'local>>492     pub fn exception_occurred(&mut self) -> Result<JThrowable<'local>> {
493         let throwable = jni_unchecked!(self.internal, ExceptionOccurred);
494         Ok(unsafe { JThrowable::from_raw(throwable) })
495     }
496 
497     /// Print exception information to the console.
exception_describe(&self) -> Result<()>498     pub fn exception_describe(&self) -> Result<()> {
499         jni_unchecked!(self.internal, ExceptionDescribe);
500         Ok(())
501     }
502 
503     /// Clear an exception in the process of being thrown. If this is never
504     /// called, the exception will continue being thrown when control is
505     /// returned to java.
exception_clear(&self) -> Result<()>506     pub fn exception_clear(&self) -> Result<()> {
507         jni_unchecked!(self.internal, ExceptionClear);
508         Ok(())
509     }
510 
511     /// Abort the JVM with an error message.
512     #[allow(unused_variables, unreachable_code)]
fatal_error<S: Into<JNIString>>(&self, msg: S) -> !513     pub fn fatal_error<S: Into<JNIString>>(&self, msg: S) -> ! {
514         let msg = msg.into();
515         let res: Result<()> = catch!({
516             jni_unchecked!(self.internal, FatalError, msg.as_ptr());
517             unreachable!()
518         });
519 
520         panic!("{:?}", res.unwrap_err());
521     }
522 
523     /// Check to see if an exception is being thrown. This only differs from
524     /// `exception_occurred` in that it doesn't return the actual thrown
525     /// exception.
exception_check(&self) -> Result<bool>526     pub fn exception_check(&self) -> Result<bool> {
527         let check = jni_unchecked!(self.internal, ExceptionCheck) == sys::JNI_TRUE;
528         Ok(check)
529     }
530 
531     /// Create a new instance of a direct java.nio.ByteBuffer
532     ///
533     /// # Example
534     /// ```rust,no_run
535     /// # use jni::{errors::Result, JNIEnv};
536     /// #
537     /// # fn example(env: &mut JNIEnv) -> Result<()> {
538     /// let buf = vec![0; 1024 * 1024];
539     /// let (addr, len) = { // (use buf.into_raw_parts() on nightly)
540     ///     let buf = buf.leak();
541     ///     (buf.as_mut_ptr(), buf.len())
542     /// };
543     /// let direct_buffer = unsafe { env.new_direct_byte_buffer(addr, len) }?;
544     /// # Ok(())
545     /// # }
546     /// ```
547     ///
548     /// # Safety
549     ///
550     /// Expects a valid (non-null) pointer and length
551     ///
552     /// Caller must ensure the lifetime of `data` extends to all uses of the returned
553     /// `ByteBuffer`. The JVM may maintain references to the `ByteBuffer` beyond the lifetime
554     /// of this `JNIEnv`.
new_direct_byte_buffer( &mut self, data: *mut u8, len: usize, ) -> Result<JByteBuffer<'local>>555     pub unsafe fn new_direct_byte_buffer(
556         &mut self,
557         data: *mut u8,
558         len: usize,
559     ) -> Result<JByteBuffer<'local>> {
560         non_null!(data, "new_direct_byte_buffer data argument");
561         let obj = jni_non_null_call!(
562             self.internal,
563             NewDirectByteBuffer,
564             data as *mut c_void,
565             len as jlong
566         );
567         Ok(JByteBuffer::from_raw(obj))
568     }
569 
570     /// Returns the starting address of the memory of the direct
571     /// java.nio.ByteBuffer.
get_direct_buffer_address(&self, buf: &JByteBuffer) -> Result<*mut u8>572     pub fn get_direct_buffer_address(&self, buf: &JByteBuffer) -> Result<*mut u8> {
573         non_null!(buf, "get_direct_buffer_address argument");
574         let ptr = jni_unchecked!(self.internal, GetDirectBufferAddress, buf.as_raw());
575         non_null!(ptr, "get_direct_buffer_address return value");
576         Ok(ptr as _)
577     }
578 
579     /// Returns the capacity (length) of the direct java.nio.ByteBuffer.
580     ///
581     /// # Terminology
582     ///
583     /// "capacity" here means the length that was passed to [`Self::new_direct_byte_buffer()`]
584     /// which does not reflect the (potentially) larger size of the underlying allocation (unlike the `Vec`
585     /// API).
586     ///
587     /// The terminology is simply kept from the original JNI API (`GetDirectBufferCapacity`).
get_direct_buffer_capacity(&self, buf: &JByteBuffer) -> Result<usize>588     pub fn get_direct_buffer_capacity(&self, buf: &JByteBuffer) -> Result<usize> {
589         non_null!(buf, "get_direct_buffer_capacity argument");
590         let capacity = jni_unchecked!(self.internal, GetDirectBufferCapacity, buf.as_raw());
591         match capacity {
592             -1 => Err(Error::JniCall(JniError::Unknown)),
593             _ => Ok(capacity as usize),
594         }
595     }
596 
597     /// Turns an object into a global ref. This has the benefit of removing the
598     /// lifetime bounds since it's guaranteed to not get GC'd by java. It
599     /// releases the GC pin upon being dropped.
new_global_ref<'other_local, O>(&self, obj: O) -> Result<GlobalRef> where O: AsRef<JObject<'other_local>>,600     pub fn new_global_ref<'other_local, O>(&self, obj: O) -> Result<GlobalRef>
601     where
602         O: AsRef<JObject<'other_local>>,
603     {
604         let jvm = self.get_java_vm()?;
605         let new_ref = jni_unchecked!(self.internal, NewGlobalRef, obj.as_ref().as_raw());
606         let global = unsafe { GlobalRef::from_raw(jvm, new_ref) };
607         Ok(global)
608     }
609 
610     /// Creates a new [weak global reference][WeakRef].
611     ///
612     /// If the provided object is null, this method returns `None`. Otherwise, it returns `Some`
613     /// containing the new weak global reference.
new_weak_ref<'other_local, O>(&self, obj: O) -> Result<Option<WeakRef>> where O: AsRef<JObject<'other_local>>,614     pub fn new_weak_ref<'other_local, O>(&self, obj: O) -> Result<Option<WeakRef>>
615     where
616         O: AsRef<JObject<'other_local>>,
617     {
618         // We need the `JavaVM` in order to construct a `WeakRef` below. But because `get_java_vm`
619         // is fallible, we need to call it before doing anything else, so that we don't leak
620         // memory if it fails.
621         let vm = self.get_java_vm()?;
622 
623         let obj = obj.as_ref().as_raw();
624 
625         // Check if the pointer is null *before* calling `NewWeakGlobalRef`.
626         //
627         // This avoids a bug in some JVM implementations which, contrary to the JNI specification,
628         // will throw `java.lang.OutOfMemoryError: C heap space` from `NewWeakGlobalRef` if it is
629         // passed a null pointer. (The specification says it will return a null pointer in that
630         // situation, not throw an exception.)
631         if obj.is_null() {
632             return Ok(None);
633         }
634 
635         let weak: sys::jweak = jni_non_void_call!(self.internal, NewWeakGlobalRef, obj);
636 
637         // Check if the pointer returned by `NewWeakGlobalRef` is null. This can happen if `obj` is
638         // itself a weak reference that was already garbage collected.
639         if weak.is_null() {
640             return Ok(None);
641         }
642 
643         let weak = unsafe { WeakRef::from_raw(vm, weak) };
644 
645         Ok(Some(weak))
646     }
647 
648     /// Create a new local reference to an object.
649     ///
650     /// Specifically, this calls the JNI function [`NewLocalRef`], which creates a reference in the
651     /// current local reference frame, regardless of whether the original reference belongs to the
652     /// same local reference frame, a different one, or is a [global reference][GlobalRef]. In Rust
653     /// terms, this method accepts a JNI reference with any valid lifetime and produces a clone of
654     /// that reference with the lifetime of this `JNIEnv`. The returned reference can outlive the
655     /// original.
656     ///
657     /// This method is useful when you have a strong global reference and you can't prevent it from
658     /// being dropped before you're finished with it. In that case, you can use this method to
659     /// create a new local reference that's guaranteed to remain valid for the duration of the
660     /// current local reference frame, regardless of what later happens to the original global
661     /// reference.
662     ///
663     /// # Lifetimes
664     ///
665     /// `'local` is the lifetime of the local reference frame that this `JNIEnv` belongs to. This
666     /// method creates a new local reference in that frame, with lifetime `'local`.
667     ///
668     /// `'other_local` is the lifetime of the original reference's frame. It can be any valid
669     /// lifetime, even one that `'local` outlives or vice versa.
670     ///
671     /// Think of `'local` as meaning `'new` and `'other_local` as meaning `'original`. (It is
672     /// unfortunately not possible to actually give these names to the two lifetimes because
673     /// `'local` is a parameter to the `JNIEnv` type, not a parameter to this method.)
674     ///
675     /// # Example
676     ///
677     /// In the following example, the `ExampleError::extract_throwable` method uses
678     /// `JNIEnv::new_local_ref` to create a new local reference that outlives the original global
679     /// reference:
680     ///
681     /// ```no_run
682     /// # use jni::{JNIEnv, objects::*};
683     /// # use std::fmt::Display;
684     /// #
685     /// # type SomeOtherErrorType = Box<dyn Display>;
686     /// #
687     /// /// An error that may be caused by either a Java exception or something going wrong in Rust
688     /// /// code.
689     /// enum ExampleError {
690     ///     /// This variant represents a Java exception.
691     ///     ///
692     ///     /// The enclosed `GlobalRef` points to a Java object of class `java.lang.Throwable`
693     ///     /// (or one of its many subclasses).
694     ///     Exception(GlobalRef),
695     ///
696     ///     /// This variant represents an error in Rust code, not a Java exception.
697     ///     Other(SomeOtherErrorType),
698     /// }
699     ///
700     /// impl ExampleError {
701     ///     /// Consumes this `ExampleError` and produces a `JThrowable`, suitable for throwing
702     ///     /// back to Java code.
703     ///     ///
704     ///     /// If this is an `ExampleError::Exception`, then this extracts the enclosed Java
705     ///     /// exception object. Otherwise, a new exception object is created to represent this
706     ///     /// error.
707     ///     fn extract_throwable<'local>(self, env: &mut JNIEnv<'local>) -> jni::errors::Result<JThrowable<'local>> {
708     ///         let throwable: JObject = match self {
709     ///             ExampleError::Exception(exception) => {
710     ///                 // The error was caused by a Java exception.
711     ///
712     ///                 // Here, `exception` is a `GlobalRef` pointing to a Java `Throwable`. It
713     ///                 // will be dropped at the end of this `match` arm. We'll use
714     ///                 // `new_local_ref` to create a local reference that will outlive the
715     ///                 // `GlobalRef`.
716     ///
717     ///                 env.new_local_ref(&exception)?
718     ///             }
719     ///
720     ///             ExampleError::Other(error) => {
721     ///                 // The error was caused by something that happened in Rust code. Create a
722     ///                 // new `java.lang.Error` to represent it.
723     ///
724     ///                 let error_string = env.new_string(error.to_string())?;
725     ///
726     ///                 env.new_object(
727     ///                     "java/lang/Error",
728     ///                     "(Ljava/lang/String;)V",
729     ///                     &[
730     ///                         (&error_string).into(),
731     ///                     ],
732     ///                 )?
733     ///             }
734     ///         };
735     ///
736     ///         Ok(JThrowable::from(throwable))
737     ///     }
738     /// }
739     /// ```
740     ///
741     /// [`NewLocalRef`]: https://docs.oracle.com/en/java/javase/11/docs/specs/jni/functions.html#newlocalref
new_local_ref<'other_local, O>(&self, obj: O) -> Result<JObject<'local>> where O: AsRef<JObject<'other_local>>,742     pub fn new_local_ref<'other_local, O>(&self, obj: O) -> Result<JObject<'local>>
743     where
744         O: AsRef<JObject<'other_local>>,
745     {
746         let local = jni_unchecked!(self.internal, NewLocalRef, obj.as_ref().as_raw());
747         Ok(unsafe { JObject::from_raw(local) })
748     }
749 
750     /// Creates a new auto-deleted local reference.
751     ///
752     /// See also [`with_local_frame`](struct.JNIEnv.html#method.with_local_frame) method that
753     /// can be more convenient when you create a _bounded_ number of local references
754     /// but cannot rely on automatic de-allocation (e.g., in case of recursion, deep call stacks,
755     /// [permanently-attached](struct.JavaVM.html#attaching-native-threads) native threads, etc.).
auto_local<O>(&self, obj: O) -> AutoLocal<'local, O> where O: Into<JObject<'local>>,756     pub fn auto_local<O>(&self, obj: O) -> AutoLocal<'local, O>
757     where
758         O: Into<JObject<'local>>,
759     {
760         AutoLocal::new(obj, self)
761     }
762 
763     /// Deletes the local reference.
764     ///
765     /// Local references are valid for the duration of a native method call.
766     /// They are
767     /// freed automatically after the native method returns. Each local
768     /// reference costs
769     /// some amount of Java Virtual Machine resource. Programmers need to make
770     /// sure that
771     /// native methods do not excessively allocate local references. Although
772     /// local
773     /// references are automatically freed after the native method returns to
774     /// Java,
775     /// excessive allocation of local references may cause the VM to run out of
776     /// memory
777     /// during the execution of a native method.
778     ///
779     /// In most cases it is better to use `AutoLocal` (see `auto_local` method)
780     /// or `with_local_frame` instead of direct `delete_local_ref` calls.
781     ///
782     /// `obj` can be a mutable borrow of a local reference (such as
783     /// `&mut JObject`) instead of the local reference itself (such as
784     /// `JObject`). In this case, the local reference will still exist after
785     /// this method returns, but it will be null.
delete_local_ref<'other_local, O>(&self, obj: O) -> Result<()> where O: Into<JObject<'other_local>>,786     pub fn delete_local_ref<'other_local, O>(&self, obj: O) -> Result<()>
787     where
788         O: Into<JObject<'other_local>>,
789     {
790         let raw = obj.into().into_raw();
791         jni_unchecked!(self.internal, DeleteLocalRef, raw);
792         Ok(())
793     }
794 
795     /// Creates a new local reference frame, in which at least a given number
796     /// of local references can be created.
797     ///
798     /// Returns `Err` on failure, with a pending `OutOfMemoryError`.
799     ///
800     /// Prefer to use
801     /// [`with_local_frame`](struct.JNIEnv.html#method.with_local_frame)
802     /// instead of direct `push_local_frame`/`pop_local_frame` calls.
803     ///
804     /// See also [`auto_local`](struct.JNIEnv.html#method.auto_local) method
805     /// and `AutoLocal` type — that approach can be more convenient in loops.
push_local_frame(&self, capacity: i32) -> Result<()>806     pub fn push_local_frame(&self, capacity: i32) -> Result<()> {
807         // This method is safe to call in case of pending exceptions (see chapter 2 of the spec)
808         let res = jni_unchecked!(self.internal, PushLocalFrame, capacity);
809         jni_error_code_to_result(res)
810     }
811 
812     /// Pops off the current local reference frame, frees all the local
813     /// references allocated on the current stack frame, except the `result`,
814     /// which is returned from this function and remains valid.
815     ///
816     /// The resulting `JObject` will be `NULL` iff `result` is `NULL`.
817     ///
818     /// This method allows direct control of local frames, but it can cause
819     /// undefined behavior and is therefore unsafe. Prefer
820     /// [`JNIEnv::with_local_frame`] instead.
821     ///
822     /// # Safety
823     ///
824     /// Any local references created after the most recent call to
825     /// [`JNIEnv::push_local_frame`] (or the underlying JNI function) must not
826     /// be used after calling this method.
pop_local_frame(&self, result: &JObject) -> Result<JObject<'local>>827     pub unsafe fn pop_local_frame(&self, result: &JObject) -> Result<JObject<'local>> {
828         // This method is safe to call in case of pending exceptions (see chapter 2 of the spec)
829         Ok(JObject::from_raw(jni_unchecked!(
830             self.internal,
831             PopLocalFrame,
832             result.as_raw()
833         )))
834     }
835 
836     /// Executes the given function in a new local reference frame, in which at least a given number
837     /// of references can be created. Once this method returns, all references allocated
838     /// in the frame are freed.
839     ///
840     /// If a frame can't be allocated with the requested capacity for local
841     /// references, returns `Err` with a pending `OutOfMemoryError`.
842     ///
843     /// Since local references created within this frame won't be accessible to the calling
844     /// frame then if you need to pass an object back to the caller then you can do that via a
845     /// [`GlobalRef`] / [`Self::make_global`].
with_local_frame<F, T, E>(&mut self, capacity: i32, f: F) -> std::result::Result<T, E> where F: FnOnce(&mut JNIEnv) -> std::result::Result<T, E>, E: From<Error>,846     pub fn with_local_frame<F, T, E>(&mut self, capacity: i32, f: F) -> std::result::Result<T, E>
847     where
848         F: FnOnce(&mut JNIEnv) -> std::result::Result<T, E>,
849         E: From<Error>,
850     {
851         unsafe {
852             self.push_local_frame(capacity)?;
853             let ret = f(self);
854             self.pop_local_frame(&JObject::null())?;
855             ret
856         }
857     }
858 
859     /// Executes the given function in a new local reference frame, in which at least a given number
860     /// of references can be created. Once this method returns, all references allocated
861     /// in the frame are freed, except the one that the function returns, which remains valid.
862     ///
863     /// If a frame can't be allocated with the requested capacity for local
864     /// references, returns `Err` with a pending `OutOfMemoryError`.
865     ///
866     /// Since the low-level JNI interface has support for passing back a single local reference
867     /// from a local frame as special-case optimization, this alternative to `with_local_frame`
868     /// exposes that capability to return a local reference without needing to create a
869     /// temporary [`GlobalRef`].
with_local_frame_returning_local<F, E>( &mut self, capacity: i32, f: F, ) -> std::result::Result<JObject<'local>, E> where F: for<'new_local> FnOnce( &mut JNIEnv<'new_local>, ) -> std::result::Result<JObject<'new_local>, E>, E: From<Error>,870     pub fn with_local_frame_returning_local<F, E>(
871         &mut self,
872         capacity: i32,
873         f: F,
874     ) -> std::result::Result<JObject<'local>, E>
875     where
876         F: for<'new_local> FnOnce(
877             &mut JNIEnv<'new_local>,
878         ) -> std::result::Result<JObject<'new_local>, E>,
879         E: From<Error>,
880     {
881         unsafe {
882             self.push_local_frame(capacity)?;
883             match f(self) {
884                 Ok(obj) => {
885                     let obj = self.pop_local_frame(&obj)?;
886                     Ok(obj)
887                 }
888                 Err(err) => {
889                     self.pop_local_frame(&JObject::null())?;
890                     Err(err)
891                 }
892             }
893         }
894     }
895 
896     /// Allocates a new object from a class descriptor without running a
897     /// constructor.
alloc_object<'other_local, T>(&mut self, class: T) -> Result<JObject<'local>> where T: Desc<'local, JClass<'other_local>>,898     pub fn alloc_object<'other_local, T>(&mut self, class: T) -> Result<JObject<'local>>
899     where
900         T: Desc<'local, JClass<'other_local>>,
901     {
902         let class = class.lookup(self)?;
903         let obj = jni_non_null_call!(self.internal, AllocObject, class.as_ref().as_raw());
904 
905         // Ensure that `class` isn't dropped before the JNI call returns.
906         drop(class);
907 
908         Ok(unsafe { JObject::from_raw(obj) })
909     }
910 
911     /// Common functionality for finding methods.
912     #[allow(clippy::redundant_closure_call)]
get_method_id_base<'other_local_1, T, U, V, C, R>( &mut self, class: T, name: U, sig: V, get_method: C, ) -> Result<R> where T: Desc<'local, JClass<'other_local_1>>, U: Into<JNIString>, V: Into<JNIString>, C: for<'other_local_2> Fn( &mut Self, &JClass<'other_local_2>, &JNIString, &JNIString, ) -> Result<R>,913     fn get_method_id_base<'other_local_1, T, U, V, C, R>(
914         &mut self,
915         class: T,
916         name: U,
917         sig: V,
918         get_method: C,
919     ) -> Result<R>
920     where
921         T: Desc<'local, JClass<'other_local_1>>,
922         U: Into<JNIString>,
923         V: Into<JNIString>,
924         C: for<'other_local_2> Fn(
925             &mut Self,
926             &JClass<'other_local_2>,
927             &JNIString,
928             &JNIString,
929         ) -> Result<R>,
930     {
931         let class = class.lookup(self)?;
932         let ffi_name = name.into();
933         let sig = sig.into();
934 
935         let res: Result<R> = catch!({ get_method(self, class.as_ref(), &ffi_name, &sig) });
936 
937         match res {
938             Ok(m) => Ok(m),
939             Err(e) => match e {
940                 Error::NullPtr(_) => {
941                     let name: String = ffi_name.into();
942                     let sig: String = sig.into();
943                     Err(Error::MethodNotFound { name, sig })
944                 }
945                 _ => Err(e),
946             },
947         }
948     }
949 
950     /// Look up a method by class descriptor, name, and
951     /// signature.
952     ///
953     /// # Example
954     /// ```rust,no_run
955     /// # use jni::{errors::Result, JNIEnv, objects::JMethodID};
956     /// #
957     /// # fn example(env: &mut JNIEnv) -> Result<()> {
958     /// let method_id: JMethodID =
959     ///     env.get_method_id("java/lang/String", "substring", "(II)Ljava/lang/String;")?;
960     /// # Ok(())
961     /// # }
962     /// ```
get_method_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JMethodID> where T: Desc<'local, JClass<'other_local>>, U: Into<JNIString>, V: Into<JNIString>,963     pub fn get_method_id<'other_local, T, U, V>(
964         &mut self,
965         class: T,
966         name: U,
967         sig: V,
968     ) -> Result<JMethodID>
969     where
970         T: Desc<'local, JClass<'other_local>>,
971         U: Into<JNIString>,
972         V: Into<JNIString>,
973     {
974         self.get_method_id_base(class, name, sig, |env, class, name, sig| {
975             let method_id = jni_non_null_call!(
976                 env.internal,
977                 GetMethodID,
978                 class.as_raw(),
979                 name.as_ptr(),
980                 sig.as_ptr()
981             );
982             Ok(unsafe { JMethodID::from_raw(method_id) })
983         })
984     }
985 
986     /// Look up a static method by class descriptor, name, and
987     /// signature.
988     ///
989     /// # Example
990     /// ```rust,no_run
991     /// # use jni::{errors::Result, JNIEnv, objects::JStaticMethodID};
992     /// #
993     /// # fn example(env: &mut JNIEnv) -> Result<()> {
994     /// let method_id: JStaticMethodID =
995     ///     env.get_static_method_id("java/lang/String", "valueOf", "(I)Ljava/lang/String;")?;
996     /// # Ok(())
997     /// # }
998     /// ```
get_static_method_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JStaticMethodID> where T: Desc<'local, JClass<'other_local>>, U: Into<JNIString>, V: Into<JNIString>,999     pub fn get_static_method_id<'other_local, T, U, V>(
1000         &mut self,
1001         class: T,
1002         name: U,
1003         sig: V,
1004     ) -> Result<JStaticMethodID>
1005     where
1006         T: Desc<'local, JClass<'other_local>>,
1007         U: Into<JNIString>,
1008         V: Into<JNIString>,
1009     {
1010         self.get_method_id_base(class, name, sig, |env, class, name, sig| {
1011             let method_id = jni_non_null_call!(
1012                 env.internal,
1013                 GetStaticMethodID,
1014                 class.as_raw(),
1015                 name.as_ptr(),
1016                 sig.as_ptr()
1017             );
1018             Ok(unsafe { JStaticMethodID::from_raw(method_id) })
1019         })
1020     }
1021 
1022     /// Look up the field ID for a class/name/type combination.
1023     ///
1024     /// # Example
1025     /// ```rust,no_run
1026     /// # use jni::{errors::Result, JNIEnv, objects::JFieldID};
1027     /// #
1028     /// # fn example(env: &mut JNIEnv) -> Result<()> {
1029     /// let field_id: JFieldID = env.get_field_id("com/my/Class", "intField", "I")?;
1030     /// # Ok(())
1031     /// # }
1032     /// ```
get_field_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JFieldID> where T: Desc<'local, JClass<'other_local>>, U: Into<JNIString>, V: Into<JNIString>,1033     pub fn get_field_id<'other_local, T, U, V>(
1034         &mut self,
1035         class: T,
1036         name: U,
1037         sig: V,
1038     ) -> Result<JFieldID>
1039     where
1040         T: Desc<'local, JClass<'other_local>>,
1041         U: Into<JNIString>,
1042         V: Into<JNIString>,
1043     {
1044         let class = class.lookup(self)?;
1045         let ffi_name = name.into();
1046         let ffi_sig = sig.into();
1047 
1048         let res: Result<JFieldID> = catch!({
1049             let field_id = jni_non_null_call!(
1050                 self.internal,
1051                 GetFieldID,
1052                 class.as_ref().as_raw(),
1053                 ffi_name.as_ptr(),
1054                 ffi_sig.as_ptr()
1055             );
1056             Ok(unsafe { JFieldID::from_raw(field_id) })
1057         });
1058 
1059         match res {
1060             Ok(m) => Ok(m),
1061             Err(e) => match e {
1062                 Error::NullPtr(_) => {
1063                     let name: String = ffi_name.into();
1064                     let sig: String = ffi_sig.into();
1065                     Err(Error::FieldNotFound { name, sig })
1066                 }
1067                 _ => Err(e),
1068             },
1069         }
1070     }
1071 
1072     /// Look up the static field ID for a class/name/type combination.
1073     ///
1074     /// # Example
1075     /// ```rust,no_run
1076     /// # use jni::{errors::Result, JNIEnv, objects::JStaticFieldID};
1077     /// #
1078     /// # fn example(env: &mut JNIEnv) -> Result<()> {
1079     /// let field_id: JStaticFieldID = env.get_static_field_id("com/my/Class", "intField", "I")?;
1080     /// # Ok(())
1081     /// # }
1082     /// ```
get_static_field_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JStaticFieldID> where T: Desc<'local, JClass<'other_local>>, U: Into<JNIString>, V: Into<JNIString>,1083     pub fn get_static_field_id<'other_local, T, U, V>(
1084         &mut self,
1085         class: T,
1086         name: U,
1087         sig: V,
1088     ) -> Result<JStaticFieldID>
1089     where
1090         T: Desc<'local, JClass<'other_local>>,
1091         U: Into<JNIString>,
1092         V: Into<JNIString>,
1093     {
1094         let class = class.lookup(self)?;
1095         let ffi_name = name.into();
1096         let ffi_sig = sig.into();
1097 
1098         let res: Result<JStaticFieldID> = catch!({
1099             let field_id = jni_non_null_call!(
1100                 self.internal,
1101                 GetStaticFieldID,
1102                 class.as_ref().as_raw(),
1103                 ffi_name.as_ptr(),
1104                 ffi_sig.as_ptr()
1105             );
1106             Ok(unsafe { JStaticFieldID::from_raw(field_id) })
1107         });
1108 
1109         // Ensure that `class` isn't dropped before the JNI call returns.
1110         drop(class);
1111 
1112         match res {
1113             Ok(m) => Ok(m),
1114             Err(e) => match e {
1115                 Error::NullPtr(_) => {
1116                     let name: String = ffi_name.into();
1117                     let sig: String = ffi_sig.into();
1118                     Err(Error::FieldNotFound { name, sig })
1119                 }
1120                 _ => Err(e),
1121             },
1122         }
1123     }
1124 
1125     /// Get the class for an object.
get_object_class<'other_local, O>(&self, obj: O) -> Result<JClass<'local>> where O: AsRef<JObject<'other_local>>,1126     pub fn get_object_class<'other_local, O>(&self, obj: O) -> Result<JClass<'local>>
1127     where
1128         O: AsRef<JObject<'other_local>>,
1129     {
1130         let obj = obj.as_ref();
1131         non_null!(obj, "get_object_class");
1132         unsafe {
1133             Ok(JClass::from_raw(jni_unchecked!(
1134                 self.internal,
1135                 GetObjectClass,
1136                 obj.as_raw()
1137             )))
1138         }
1139     }
1140 
1141     /// Call a static method in an unsafe manner. This does nothing to check
1142     /// whether the method is valid to call on the class, whether the return
1143     /// type is correct, or whether the number of args is valid for the method.
1144     ///
1145     /// Under the hood, this simply calls the `CallStatic<Type>MethodA` method
1146     /// with the provided arguments.
1147     ///
1148     /// # Safety
1149     ///
1150     /// The provided JMethodID must be valid, and match the types and number of arguments, and return type.
1151     /// If these are incorrect, the JVM may crash. The JMethodID must also match the passed type.
call_static_method_unchecked<'other_local, T, U>( &mut self, class: T, method_id: U, ret: ReturnType, args: &[jvalue], ) -> Result<JValueOwned<'local>> where T: Desc<'local, JClass<'other_local>>, U: Desc<'local, JStaticMethodID>,1152     pub unsafe fn call_static_method_unchecked<'other_local, T, U>(
1153         &mut self,
1154         class: T,
1155         method_id: U,
1156         ret: ReturnType,
1157         args: &[jvalue],
1158     ) -> Result<JValueOwned<'local>>
1159     where
1160         T: Desc<'local, JClass<'other_local>>,
1161         U: Desc<'local, JStaticMethodID>,
1162     {
1163         let class = class.lookup(self)?;
1164 
1165         let method_id = method_id.lookup(self)?.as_ref().into_raw();
1166 
1167         let class_raw = class.as_ref().as_raw();
1168         let jni_args = args.as_ptr();
1169 
1170         // TODO clean this up
1171         let ret = Ok(match ret {
1172             ReturnType::Object | ReturnType::Array => {
1173                 let obj = jni_non_void_call!(
1174                     self.internal,
1175                     CallStaticObjectMethodA,
1176                     class_raw,
1177                     method_id,
1178                     jni_args
1179                 );
1180                 let obj = unsafe { JObject::from_raw(obj) };
1181                 obj.into()
1182             }
1183             ReturnType::Primitive(p) => match p {
1184                 Primitive::Boolean => jni_non_void_call!(
1185                     self.internal,
1186                     CallStaticBooleanMethodA,
1187                     class_raw,
1188                     method_id,
1189                     jni_args
1190                 )
1191                 .into(),
1192                 Primitive::Char => jni_non_void_call!(
1193                     self.internal,
1194                     CallStaticCharMethodA,
1195                     class_raw,
1196                     method_id,
1197                     jni_args
1198                 )
1199                 .into(),
1200                 Primitive::Short => jni_non_void_call!(
1201                     self.internal,
1202                     CallStaticShortMethodA,
1203                     class_raw,
1204                     method_id,
1205                     jni_args
1206                 )
1207                 .into(),
1208                 Primitive::Int => jni_non_void_call!(
1209                     self.internal,
1210                     CallStaticIntMethodA,
1211                     class_raw,
1212                     method_id,
1213                     jni_args
1214                 )
1215                 .into(),
1216                 Primitive::Long => jni_non_void_call!(
1217                     self.internal,
1218                     CallStaticLongMethodA,
1219                     class_raw,
1220                     method_id,
1221                     jni_args
1222                 )
1223                 .into(),
1224                 Primitive::Float => jni_non_void_call!(
1225                     self.internal,
1226                     CallStaticFloatMethodA,
1227                     class_raw,
1228                     method_id,
1229                     jni_args
1230                 )
1231                 .into(),
1232                 Primitive::Double => jni_non_void_call!(
1233                     self.internal,
1234                     CallStaticDoubleMethodA,
1235                     class_raw,
1236                     method_id,
1237                     jni_args
1238                 )
1239                 .into(),
1240                 Primitive::Byte => jni_non_void_call!(
1241                     self.internal,
1242                     CallStaticByteMethodA,
1243                     class_raw,
1244                     method_id,
1245                     jni_args
1246                 )
1247                 .into(),
1248                 Primitive::Void => {
1249                     jni_void_call!(
1250                         self.internal,
1251                         CallStaticVoidMethodA,
1252                         class_raw,
1253                         method_id,
1254                         jni_args
1255                     );
1256                     return Ok(JValueOwned::Void);
1257                 }
1258             }, // JavaType::Primitive
1259         }); // match parsed.ret
1260 
1261         // Ensure that `class` isn't dropped before the JNI call returns.
1262         drop(class);
1263 
1264         ret
1265     }
1266 
1267     /// Call an object method in an unsafe manner. This does nothing to check
1268     /// whether the method is valid to call on the object, whether the return
1269     /// type is correct, or whether the number of args is valid for the method.
1270     ///
1271     /// Under the hood, this simply calls the `Call<Type>MethodA` method with
1272     /// the provided arguments.
1273     ///
1274     /// # Safety
1275     ///
1276     /// The provided JMethodID must be valid, and match the types and number of arguments, and return type.
1277     /// If these are incorrect, the JVM may crash. The JMethodID must also match the passed type.
call_method_unchecked<'other_local, O, T>( &mut self, obj: O, method_id: T, ret: ReturnType, args: &[jvalue], ) -> Result<JValueOwned<'local>> where O: AsRef<JObject<'other_local>>, T: Desc<'local, JMethodID>,1278     pub unsafe fn call_method_unchecked<'other_local, O, T>(
1279         &mut self,
1280         obj: O,
1281         method_id: T,
1282         ret: ReturnType,
1283         args: &[jvalue],
1284     ) -> Result<JValueOwned<'local>>
1285     where
1286         O: AsRef<JObject<'other_local>>,
1287         T: Desc<'local, JMethodID>,
1288     {
1289         let method_id = method_id.lookup(self)?.as_ref().into_raw();
1290 
1291         let obj = obj.as_ref().as_raw();
1292 
1293         let jni_args = args.as_ptr();
1294 
1295         // TODO clean this up
1296         Ok(match ret {
1297             ReturnType::Object | ReturnType::Array => {
1298                 let obj =
1299                     jni_non_void_call!(self.internal, CallObjectMethodA, obj, method_id, jni_args);
1300                 let obj = unsafe { JObject::from_raw(obj) };
1301                 obj.into()
1302             }
1303             ReturnType::Primitive(p) => match p {
1304                 Primitive::Boolean => {
1305                     jni_non_void_call!(self.internal, CallBooleanMethodA, obj, method_id, jni_args)
1306                         .into()
1307                 }
1308                 Primitive::Char => {
1309                     jni_non_void_call!(self.internal, CallCharMethodA, obj, method_id, jni_args)
1310                         .into()
1311                 }
1312                 Primitive::Short => {
1313                     jni_non_void_call!(self.internal, CallShortMethodA, obj, method_id, jni_args)
1314                         .into()
1315                 }
1316                 Primitive::Int => {
1317                     jni_non_void_call!(self.internal, CallIntMethodA, obj, method_id, jni_args)
1318                         .into()
1319                 }
1320                 Primitive::Long => {
1321                     jni_non_void_call!(self.internal, CallLongMethodA, obj, method_id, jni_args)
1322                         .into()
1323                 }
1324                 Primitive::Float => {
1325                     jni_non_void_call!(self.internal, CallFloatMethodA, obj, method_id, jni_args)
1326                         .into()
1327                 }
1328                 Primitive::Double => {
1329                     jni_non_void_call!(self.internal, CallDoubleMethodA, obj, method_id, jni_args)
1330                         .into()
1331                 }
1332                 Primitive::Byte => {
1333                     jni_non_void_call!(self.internal, CallByteMethodA, obj, method_id, jni_args)
1334                         .into()
1335                 }
1336                 Primitive::Void => {
1337                     jni_void_call!(self.internal, CallVoidMethodA, obj, method_id, jni_args);
1338                     return Ok(JValueOwned::Void);
1339                 }
1340             }, // JavaType::Primitive
1341         }) // match parsed.ret
1342     }
1343 
1344     /// Calls an object method safely. This comes with a number of
1345     /// lookups/checks. It
1346     ///
1347     /// * Parses the type signature to find the number of arguments and return
1348     ///   type
1349     /// * Looks up the JClass for the given object.
1350     /// * Looks up the JMethodID for the class/name/signature combination
1351     /// * Ensures that the number/types of args matches the signature
1352     ///   * Cannot check an object's type - but primitive types are matched against each other (including Object)
1353     /// * Calls `call_method_unchecked` with the verified safe arguments.
1354     ///
1355     /// Note: this may cause a Java exception if the arguments are the wrong
1356     /// type, in addition to if the method itself throws.
call_method<'other_local, O, S, T>( &mut self, obj: O, name: S, sig: T, args: &[JValue], ) -> Result<JValueOwned<'local>> where O: AsRef<JObject<'other_local>>, S: Into<JNIString>, T: Into<JNIString> + AsRef<str>,1357     pub fn call_method<'other_local, O, S, T>(
1358         &mut self,
1359         obj: O,
1360         name: S,
1361         sig: T,
1362         args: &[JValue],
1363     ) -> Result<JValueOwned<'local>>
1364     where
1365         O: AsRef<JObject<'other_local>>,
1366         S: Into<JNIString>,
1367         T: Into<JNIString> + AsRef<str>,
1368     {
1369         let obj = obj.as_ref();
1370         non_null!(obj, "call_method obj argument");
1371 
1372         // parse the signature
1373         let parsed = TypeSignature::from_str(sig.as_ref())?;
1374         if parsed.args.len() != args.len() {
1375             return Err(Error::InvalidArgList(parsed));
1376         }
1377 
1378         // check arguments types
1379         let base_types_match = parsed
1380             .args
1381             .iter()
1382             .zip(args.iter())
1383             .all(|(exp, act)| match exp {
1384                 JavaType::Primitive(p) => act.primitive_type() == Some(*p),
1385                 JavaType::Object(_) | JavaType::Array(_) => act.primitive_type().is_none(),
1386                 JavaType::Method(_) => {
1387                     unreachable!("JavaType::Method(_) should not come from parsing a method sig")
1388                 }
1389             });
1390         if !base_types_match {
1391             return Err(Error::InvalidArgList(parsed));
1392         }
1393 
1394         let class = self.auto_local(self.get_object_class(obj)?);
1395 
1396         let args: Vec<jvalue> = args.iter().map(|v| v.as_jni()).collect();
1397 
1398         // SAFETY: We've obtained the method_id above, so it is valid for this class.
1399         // We've also validated the argument counts and types using the same type signature
1400         // we fetched the original method ID from.
1401         unsafe { self.call_method_unchecked(obj, (&class, name, sig), parsed.ret, &args) }
1402     }
1403 
1404     /// Calls a static method safely. This comes with a number of
1405     /// lookups/checks. It
1406     ///
1407     /// * Parses the type signature to find the number of arguments and return
1408     ///   type
1409     /// * Looks up the JMethodID for the class/name/signature combination
1410     /// * Ensures that the number/types of args matches the signature
1411     ///   * Cannot check an object's type - but primitive types are matched against each other (including Object)
1412     /// * Calls `call_method_unchecked` with the verified safe arguments.
1413     ///
1414     /// Note: this may cause a Java exception if the arguments are the wrong
1415     /// type, in addition to if the method itself throws.
call_static_method<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, args: &[JValue], ) -> Result<JValueOwned<'local>> where T: Desc<'local, JClass<'other_local>>, U: Into<JNIString>, V: Into<JNIString> + AsRef<str>,1416     pub fn call_static_method<'other_local, T, U, V>(
1417         &mut self,
1418         class: T,
1419         name: U,
1420         sig: V,
1421         args: &[JValue],
1422     ) -> Result<JValueOwned<'local>>
1423     where
1424         T: Desc<'local, JClass<'other_local>>,
1425         U: Into<JNIString>,
1426         V: Into<JNIString> + AsRef<str>,
1427     {
1428         let parsed = TypeSignature::from_str(&sig)?;
1429         if parsed.args.len() != args.len() {
1430             return Err(Error::InvalidArgList(parsed));
1431         }
1432 
1433         // check arguments types
1434         let base_types_match = parsed
1435             .args
1436             .iter()
1437             .zip(args.iter())
1438             .all(|(exp, act)| match exp {
1439                 JavaType::Primitive(p) => act.primitive_type() == Some(*p),
1440                 JavaType::Object(_) | JavaType::Array(_) => act.primitive_type().is_none(),
1441                 JavaType::Method(_) => {
1442                     unreachable!("JavaType::Method(_) should not come from parsing a method sig")
1443                 }
1444             });
1445         if !base_types_match {
1446             return Err(Error::InvalidArgList(parsed));
1447         }
1448 
1449         // go ahead and look up the class since we'll need that for the next call.
1450         let class = class.lookup(self)?;
1451         let class = class.as_ref();
1452 
1453         let args: Vec<jvalue> = args.iter().map(|v| v.as_jni()).collect();
1454 
1455         // SAFETY: We've obtained the method_id above, so it is valid for this class.
1456         // We've also validated the argument counts and types using the same type signature
1457         // we fetched the original method ID from.
1458         unsafe { self.call_static_method_unchecked(class, (class, name, sig), parsed.ret, &args) }
1459     }
1460 
1461     /// Create a new object using a constructor. This is done safely using
1462     /// checks similar to those in `call_static_method`.
new_object<'other_local, T, U>( &mut self, class: T, ctor_sig: U, ctor_args: &[JValue], ) -> Result<JObject<'local>> where T: Desc<'local, JClass<'other_local>>, U: Into<JNIString> + AsRef<str>,1463     pub fn new_object<'other_local, T, U>(
1464         &mut self,
1465         class: T,
1466         ctor_sig: U,
1467         ctor_args: &[JValue],
1468     ) -> Result<JObject<'local>>
1469     where
1470         T: Desc<'local, JClass<'other_local>>,
1471         U: Into<JNIString> + AsRef<str>,
1472     {
1473         // parse the signature
1474         let parsed = TypeSignature::from_str(&ctor_sig)?;
1475 
1476         // check arguments length
1477         if parsed.args.len() != ctor_args.len() {
1478             return Err(Error::InvalidArgList(parsed));
1479         }
1480 
1481         // check arguments types
1482         let base_types_match =
1483             parsed
1484                 .args
1485                 .iter()
1486                 .zip(ctor_args.iter())
1487                 .all(|(exp, act)| match exp {
1488                     JavaType::Primitive(p) => act.primitive_type() == Some(*p),
1489                     JavaType::Object(_) | JavaType::Array(_) => act.primitive_type().is_none(),
1490                     JavaType::Method(_) => {
1491                         unreachable!("JavaType::Method(_) should not come from parsing a ctor sig")
1492                     }
1493                 });
1494         if !base_types_match {
1495             return Err(Error::InvalidArgList(parsed));
1496         }
1497 
1498         // check return value
1499         if parsed.ret != ReturnType::Primitive(Primitive::Void) {
1500             return Err(Error::InvalidCtorReturn);
1501         }
1502 
1503         // build strings
1504         let class = class.lookup(self)?;
1505         let class = class.as_ref();
1506 
1507         let method_id: JMethodID = Desc::<JMethodID>::lookup((class, ctor_sig), self)?;
1508 
1509         let ctor_args: Vec<jvalue> = ctor_args.iter().map(|v| v.as_jni()).collect();
1510         // SAFETY: We've obtained the method_id above, so it is valid for this class.
1511         // We've also validated the argument counts and types using the same type signature
1512         // we fetched the original method ID from.
1513         unsafe { self.new_object_unchecked(class, method_id, &ctor_args) }
1514     }
1515 
1516     /// Create a new object using a constructor. Arguments aren't checked
1517     /// because of the `JMethodID` usage.
1518     ///
1519     /// # Safety
1520     ///
1521     /// The provided JMethodID must be valid, and match the types and number of arguments, as well as return type
1522     /// (always an Object for a constructor). If these are incorrect, the JVM may crash.  The JMethodID must also match
1523     /// the passed type.
new_object_unchecked<'other_local, T>( &mut self, class: T, ctor_id: JMethodID, ctor_args: &[jvalue], ) -> Result<JObject<'local>> where T: Desc<'local, JClass<'other_local>>,1524     pub unsafe fn new_object_unchecked<'other_local, T>(
1525         &mut self,
1526         class: T,
1527         ctor_id: JMethodID,
1528         ctor_args: &[jvalue],
1529     ) -> Result<JObject<'local>>
1530     where
1531         T: Desc<'local, JClass<'other_local>>,
1532     {
1533         let class = class.lookup(self)?;
1534 
1535         let jni_args = ctor_args.as_ptr();
1536 
1537         let obj = jni_non_null_call!(
1538             self.internal,
1539             NewObjectA,
1540             class.as_ref().as_raw(),
1541             ctor_id.into_raw(),
1542             jni_args
1543         );
1544 
1545         // Ensure that `class` isn't dropped before the JNI call returns.
1546         drop(class);
1547 
1548         Ok(unsafe { JObject::from_raw(obj) })
1549     }
1550 
1551     /// Cast a JObject to a `JList`. This won't throw exceptions or return errors
1552     /// in the event that the object isn't actually a list, but the methods on
1553     /// the resulting map object will.
get_list<'other_local_1, 'obj_ref>( &mut self, obj: &'obj_ref JObject<'other_local_1>, ) -> Result<JList<'local, 'other_local_1, 'obj_ref>> where 'other_local_1: 'obj_ref,1554     pub fn get_list<'other_local_1, 'obj_ref>(
1555         &mut self,
1556         obj: &'obj_ref JObject<'other_local_1>,
1557     ) -> Result<JList<'local, 'other_local_1, 'obj_ref>>
1558     where
1559         'other_local_1: 'obj_ref,
1560     {
1561         non_null!(obj, "get_list obj argument");
1562         JList::from_env(self, obj)
1563     }
1564 
1565     /// Cast a JObject to a JMap. This won't throw exceptions or return errors
1566     /// in the event that the object isn't actually a map, but the methods on
1567     /// the resulting map object will.
get_map<'other_local_1, 'obj_ref>( &mut self, obj: &'obj_ref JObject<'other_local_1>, ) -> Result<JMap<'local, 'other_local_1, 'obj_ref>> where 'other_local_1: 'obj_ref,1568     pub fn get_map<'other_local_1, 'obj_ref>(
1569         &mut self,
1570         obj: &'obj_ref JObject<'other_local_1>,
1571     ) -> Result<JMap<'local, 'other_local_1, 'obj_ref>>
1572     where
1573         'other_local_1: 'obj_ref,
1574     {
1575         non_null!(obj, "get_map obj argument");
1576         JMap::from_env(self, obj)
1577     }
1578 
1579     /// Get a [`JavaStr`] from a [`JString`]. This allows conversions from java string
1580     /// objects to rust strings.
1581     ///
1582     /// This only entails calling `GetStringUTFChars`, which will return a [`JavaStr`] in Java's
1583     /// [Modified UTF-8](https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8)
1584     /// format.
1585     ///
1586     /// This doesn't automatically decode Java's modified UTF-8 format but you
1587     /// can use `.into()` to convert the returned [`JavaStr`] into a Rust [`String`].
1588     ///
1589     /// # Safety
1590     ///
1591     /// The caller must guarantee that the Object passed in is an instance of `java.lang.String`,
1592     /// passing in anything else will lead to undefined behaviour (The JNI implementation
1593     /// is likely to crash or abort the process).
1594     ///
1595     /// # Errors
1596     ///
1597     /// Returns an error if `obj` is `null`
get_string_unchecked<'other_local: 'obj_ref, 'obj_ref>( &self, obj: &'obj_ref JString<'other_local>, ) -> Result<JavaStr<'local, 'other_local, 'obj_ref>>1598     pub unsafe fn get_string_unchecked<'other_local: 'obj_ref, 'obj_ref>(
1599         &self,
1600         obj: &'obj_ref JString<'other_local>,
1601     ) -> Result<JavaStr<'local, 'other_local, 'obj_ref>> {
1602         non_null!(obj, "get_string obj argument");
1603         JavaStr::from_env(self, obj)
1604     }
1605 
1606     /// Get a [`JavaStr`] from a [`JString`]. This allows conversions from java string
1607     /// objects to rust strings.
1608     ///
1609     /// This entails checking that the given object is a `java.lang.String` and
1610     /// calling `GetStringUTFChars`, which will return a [`JavaStr`] in Java's
1611     /// [Modified UTF-8](https://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8)
1612     /// format.
1613     ///
1614     /// This doesn't automatically decode Java's modified UTF-8 format but you
1615     /// can use `.into()` to convert the returned [`JavaStr`] into a Rust [`String`].
1616     ///
1617     /// # Performance
1618     ///
1619     /// This function has a large relative performance impact compared to
1620     /// [Self::get_string_unchecked]. For example it may be about five times
1621     /// slower than `get_string_unchecked` for very short string. This
1622     /// performance penalty comes from the extra validation performed by this
1623     /// function. If and only if you can guarantee that your `obj` is of
1624     /// `java.lang.String`, use [Self::get_string_unchecked].
1625     ///
1626     /// # Errors
1627     ///
1628     /// Returns an error if `obj` is `null` or is not an instance of `java.lang.String`
get_string<'other_local: 'obj_ref, 'obj_ref>( &mut self, obj: &'obj_ref JString<'other_local>, ) -> Result<JavaStr<'local, 'other_local, 'obj_ref>>1629     pub fn get_string<'other_local: 'obj_ref, 'obj_ref>(
1630         &mut self,
1631         obj: &'obj_ref JString<'other_local>,
1632     ) -> Result<JavaStr<'local, 'other_local, 'obj_ref>> {
1633         let string_class = self.find_class("java/lang/String")?;
1634         if !self.is_assignable_from(string_class, self.get_object_class(obj)?)? {
1635             return Err(JniCall(JniError::InvalidArguments));
1636         }
1637 
1638         // SAFETY: We check that the passed in Object is actually a java.lang.String
1639         unsafe { self.get_string_unchecked(obj) }
1640     }
1641 
1642     /// Create a new java string object from a rust string. This requires a
1643     /// re-encoding of rusts *real* UTF-8 strings to java's modified UTF-8
1644     /// format.
new_string<S: Into<JNIString>>(&self, from: S) -> Result<JString<'local>>1645     pub fn new_string<S: Into<JNIString>>(&self, from: S) -> Result<JString<'local>> {
1646         let ffi_str = from.into();
1647         let s = jni_non_null_call!(self.internal, NewStringUTF, ffi_str.as_ptr());
1648         Ok(unsafe { JString::from_raw(s) })
1649     }
1650 
1651     /// Get the length of a [`JPrimitiveArray`] or [`JObjectArray`].
get_array_length<'other_local, 'array>( &self, array: &'array impl AsJArrayRaw<'other_local>, ) -> Result<jsize>1652     pub fn get_array_length<'other_local, 'array>(
1653         &self,
1654         array: &'array impl AsJArrayRaw<'other_local>,
1655     ) -> Result<jsize> {
1656         non_null!(array.as_jarray_raw(), "get_array_length array argument");
1657         let len: jsize = jni_unchecked!(self.internal, GetArrayLength, array.as_jarray_raw());
1658         Ok(len)
1659     }
1660 
1661     /// Construct a new array holding objects in class `element_class`.
1662     /// All elements are initially set to `initial_element`.
1663     ///
1664     /// This function returns a local reference, that must not be allocated
1665     /// excessively.
1666     /// See [Java documentation][1] for details.
1667     ///
1668     /// [1]: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references
new_object_array<'other_local_1, 'other_local_2, T, U>( &mut self, length: jsize, element_class: T, initial_element: U, ) -> Result<JObjectArray<'local>> where T: Desc<'local, JClass<'other_local_2>>, U: AsRef<JObject<'other_local_1>>,1669     pub fn new_object_array<'other_local_1, 'other_local_2, T, U>(
1670         &mut self,
1671         length: jsize,
1672         element_class: T,
1673         initial_element: U,
1674     ) -> Result<JObjectArray<'local>>
1675     where
1676         T: Desc<'local, JClass<'other_local_2>>,
1677         U: AsRef<JObject<'other_local_1>>,
1678     {
1679         let class = element_class.lookup(self)?;
1680 
1681         let array: jarray = jni_non_null_call!(
1682             self.internal,
1683             NewObjectArray,
1684             length,
1685             class.as_ref().as_raw(),
1686             initial_element.as_ref().as_raw()
1687         );
1688 
1689         let array = unsafe { JObjectArray::from_raw(array) };
1690 
1691         // Ensure that `class` isn't dropped before the JNI call returns.
1692         drop(class);
1693 
1694         Ok(array)
1695     }
1696 
1697     /// Returns a local reference to an element of the [`JObjectArray`] `array`.
get_object_array_element<'other_local>( &mut self, array: impl AsRef<JObjectArray<'other_local>>, index: jsize, ) -> Result<JObject<'local>>1698     pub fn get_object_array_element<'other_local>(
1699         &mut self,
1700         array: impl AsRef<JObjectArray<'other_local>>,
1701         index: jsize,
1702     ) -> Result<JObject<'local>> {
1703         non_null!(array.as_ref(), "get_object_array_element array argument");
1704         Ok(unsafe {
1705             JObject::from_raw(jni_non_void_call!(
1706                 self.internal,
1707                 GetObjectArrayElement,
1708                 array.as_ref().as_raw(),
1709                 index
1710             ))
1711         })
1712     }
1713 
1714     /// Sets an element of the [`JObjectArray`] `array`.
set_object_array_element<'other_local_1, 'other_local_2>( &self, array: impl AsRef<JObjectArray<'other_local_1>>, index: jsize, value: impl AsRef<JObject<'other_local_2>>, ) -> Result<()>1715     pub fn set_object_array_element<'other_local_1, 'other_local_2>(
1716         &self,
1717         array: impl AsRef<JObjectArray<'other_local_1>>,
1718         index: jsize,
1719         value: impl AsRef<JObject<'other_local_2>>,
1720     ) -> Result<()> {
1721         non_null!(array.as_ref(), "set_object_array_element array argument");
1722         jni_void_call!(
1723             self.internal,
1724             SetObjectArrayElement,
1725             array.as_ref().as_raw(),
1726             index,
1727             value.as_ref().as_raw()
1728         );
1729         Ok(())
1730     }
1731 
1732     /// Create a new java byte array from a rust byte slice.
byte_array_from_slice(&self, buf: &[u8]) -> Result<JByteArray<'local>>1733     pub fn byte_array_from_slice(&self, buf: &[u8]) -> Result<JByteArray<'local>> {
1734         let length = buf.len() as i32;
1735         let bytes = self.new_byte_array(length)?;
1736         jni_unchecked!(
1737             self.internal,
1738             SetByteArrayRegion,
1739             bytes.as_raw(),
1740             0,
1741             length,
1742             buf.as_ptr() as *const i8
1743         );
1744         Ok(bytes)
1745     }
1746 
1747     /// Converts a java byte array to a rust vector of bytes.
convert_byte_array<'other_local>( &self, array: impl AsRef<JByteArray<'other_local>>, ) -> Result<Vec<u8>>1748     pub fn convert_byte_array<'other_local>(
1749         &self,
1750         array: impl AsRef<JByteArray<'other_local>>,
1751     ) -> Result<Vec<u8>> {
1752         let array = array.as_ref().as_raw();
1753         non_null!(array, "convert_byte_array array argument");
1754         let length = jni_non_void_call!(self.internal, GetArrayLength, array);
1755         let mut vec = vec![0u8; length as usize];
1756         jni_unchecked!(
1757             self.internal,
1758             GetByteArrayRegion,
1759             array,
1760             0,
1761             length,
1762             vec.as_mut_ptr() as *mut i8
1763         );
1764         Ok(vec)
1765     }
1766 
1767     /// Create a new java boolean array of supplied length.
new_boolean_array(&self, length: jsize) -> Result<JBooleanArray<'local>>1768     pub fn new_boolean_array(&self, length: jsize) -> Result<JBooleanArray<'local>> {
1769         let array: jarray = jni_non_null_call!(self.internal, NewBooleanArray, length);
1770         let array = unsafe { JBooleanArray::from_raw(array) };
1771         Ok(array)
1772     }
1773 
1774     /// Create a new java byte array of supplied length.
new_byte_array(&self, length: jsize) -> Result<JByteArray<'local>>1775     pub fn new_byte_array(&self, length: jsize) -> Result<JByteArray<'local>> {
1776         let array: jarray = jni_non_null_call!(self.internal, NewByteArray, length);
1777         let array = unsafe { JByteArray::from_raw(array) };
1778         Ok(array)
1779     }
1780 
1781     /// Create a new java char array of supplied length.
new_char_array(&self, length: jsize) -> Result<JCharArray<'local>>1782     pub fn new_char_array(&self, length: jsize) -> Result<JCharArray<'local>> {
1783         let array: jarray = jni_non_null_call!(self.internal, NewCharArray, length);
1784         let array = unsafe { JCharArray::from_raw(array) };
1785         Ok(array)
1786     }
1787 
1788     /// Create a new java short array of supplied length.
new_short_array(&self, length: jsize) -> Result<JShortArray<'local>>1789     pub fn new_short_array(&self, length: jsize) -> Result<JShortArray<'local>> {
1790         let array: jarray = jni_non_null_call!(self.internal, NewShortArray, length);
1791         let array = unsafe { JShortArray::from_raw(array) };
1792         Ok(array)
1793     }
1794 
1795     /// Create a new java int array of supplied length.
new_int_array(&self, length: jsize) -> Result<JIntArray<'local>>1796     pub fn new_int_array(&self, length: jsize) -> Result<JIntArray<'local>> {
1797         let array: jarray = jni_non_null_call!(self.internal, NewIntArray, length);
1798         let array = unsafe { JIntArray::from_raw(array) };
1799         Ok(array)
1800     }
1801 
1802     /// Create a new java long array of supplied length.
new_long_array(&self, length: jsize) -> Result<JLongArray<'local>>1803     pub fn new_long_array(&self, length: jsize) -> Result<JLongArray<'local>> {
1804         let array: jarray = jni_non_null_call!(self.internal, NewLongArray, length);
1805         let array = unsafe { JLongArray::from_raw(array) };
1806         Ok(array)
1807     }
1808 
1809     /// Create a new java float array of supplied length.
new_float_array(&self, length: jsize) -> Result<JFloatArray<'local>>1810     pub fn new_float_array(&self, length: jsize) -> Result<JFloatArray<'local>> {
1811         let array: jarray = jni_non_null_call!(self.internal, NewFloatArray, length);
1812         let array = unsafe { JFloatArray::from_raw(array) };
1813         Ok(array)
1814     }
1815 
1816     /// Create a new java double array of supplied length.
new_double_array(&self, length: jsize) -> Result<JDoubleArray<'local>>1817     pub fn new_double_array(&self, length: jsize) -> Result<JDoubleArray<'local>> {
1818         let array: jarray = jni_non_null_call!(self.internal, NewDoubleArray, length);
1819         let array = unsafe { JDoubleArray::from_raw(array) };
1820         Ok(array)
1821     }
1822 
1823     /// Copy elements of the java boolean array from the `start` index to the
1824     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1825     ///
1826     /// # Errors
1827     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1828     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1829     /// and `Err` is returned.
1830     ///
1831     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_boolean_array_region<'other_local>( &self, array: impl AsRef<JBooleanArray<'other_local>>, start: jsize, buf: &mut [jboolean], ) -> Result<()>1832     pub fn get_boolean_array_region<'other_local>(
1833         &self,
1834         array: impl AsRef<JBooleanArray<'other_local>>,
1835         start: jsize,
1836         buf: &mut [jboolean],
1837     ) -> Result<()> {
1838         non_null!(array.as_ref(), "get_boolean_array_region array argument");
1839         jni_void_call!(
1840             self.internal,
1841             GetBooleanArrayRegion,
1842             array.as_ref().as_raw(),
1843             start,
1844             buf.len() as jsize,
1845             buf.as_mut_ptr()
1846         );
1847         Ok(())
1848     }
1849 
1850     /// Copy elements of the java byte array from the `start` index to the `buf`
1851     /// slice. The number of copied elements is equal to the `buf` length.
1852     ///
1853     /// # Errors
1854     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1855     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1856     /// and `Err` is returned.
1857     ///
1858     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_byte_array_region<'other_local>( &self, array: impl AsRef<JByteArray<'other_local>>, start: jsize, buf: &mut [jbyte], ) -> Result<()>1859     pub fn get_byte_array_region<'other_local>(
1860         &self,
1861         array: impl AsRef<JByteArray<'other_local>>,
1862         start: jsize,
1863         buf: &mut [jbyte],
1864     ) -> Result<()> {
1865         non_null!(array.as_ref(), "get_byte_array_region array argument");
1866         jni_void_call!(
1867             self.internal,
1868             GetByteArrayRegion,
1869             array.as_ref().as_raw(),
1870             start,
1871             buf.len() as jsize,
1872             buf.as_mut_ptr()
1873         );
1874 
1875         Ok(())
1876     }
1877 
1878     /// Copy elements of the java char array from the `start` index to the
1879     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1880     ///
1881     /// # Errors
1882     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1883     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1884     /// and `Err` is returned.
1885     ///
1886     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_char_array_region<'other_local>( &self, array: impl AsRef<JCharArray<'other_local>>, start: jsize, buf: &mut [jchar], ) -> Result<()>1887     pub fn get_char_array_region<'other_local>(
1888         &self,
1889         array: impl AsRef<JCharArray<'other_local>>,
1890         start: jsize,
1891         buf: &mut [jchar],
1892     ) -> Result<()> {
1893         non_null!(array.as_ref(), "get_char_array_region array argument");
1894         jni_void_call!(
1895             self.internal,
1896             GetCharArrayRegion,
1897             array.as_ref().as_raw(),
1898             start,
1899             buf.len() as jsize,
1900             buf.as_mut_ptr()
1901         );
1902         Ok(())
1903     }
1904 
1905     /// Copy elements of the java short array from the `start` index to the
1906     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1907     ///
1908     /// # Errors
1909     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1910     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1911     /// and `Err` is returned.
1912     ///
1913     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_short_array_region<'other_local>( &self, array: impl AsRef<JShortArray<'other_local>>, start: jsize, buf: &mut [jshort], ) -> Result<()>1914     pub fn get_short_array_region<'other_local>(
1915         &self,
1916         array: impl AsRef<JShortArray<'other_local>>,
1917         start: jsize,
1918         buf: &mut [jshort],
1919     ) -> Result<()> {
1920         non_null!(array.as_ref(), "get_short_array_region array argument");
1921         jni_void_call!(
1922             self.internal,
1923             GetShortArrayRegion,
1924             array.as_ref().as_raw(),
1925             start,
1926             buf.len() as jsize,
1927             buf.as_mut_ptr()
1928         );
1929         Ok(())
1930     }
1931 
1932     /// Copy elements of the java int array from the `start` index to the
1933     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1934     ///
1935     /// # Errors
1936     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1937     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1938     /// and `Err` is returned.
1939     ///
1940     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_int_array_region<'other_local>( &self, array: impl AsRef<JIntArray<'other_local>>, start: jsize, buf: &mut [jint], ) -> Result<()>1941     pub fn get_int_array_region<'other_local>(
1942         &self,
1943         array: impl AsRef<JIntArray<'other_local>>,
1944         start: jsize,
1945         buf: &mut [jint],
1946     ) -> Result<()> {
1947         non_null!(array.as_ref(), "get_int_array_region array argument");
1948         jni_void_call!(
1949             self.internal,
1950             GetIntArrayRegion,
1951             array.as_ref().as_raw(),
1952             start,
1953             buf.len() as jsize,
1954             buf.as_mut_ptr()
1955         );
1956         Ok(())
1957     }
1958 
1959     /// Copy elements of the java long array from the `start` index to the
1960     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1961     ///
1962     /// # Errors
1963     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1964     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1965     /// and `Err` is returned.
1966     ///
1967     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_long_array_region<'other_local>( &self, array: impl AsRef<JLongArray<'other_local>>, start: jsize, buf: &mut [jlong], ) -> Result<()>1968     pub fn get_long_array_region<'other_local>(
1969         &self,
1970         array: impl AsRef<JLongArray<'other_local>>,
1971         start: jsize,
1972         buf: &mut [jlong],
1973     ) -> Result<()> {
1974         non_null!(array.as_ref(), "get_long_array_region array argument");
1975         jni_void_call!(
1976             self.internal,
1977             GetLongArrayRegion,
1978             array.as_ref().as_raw(),
1979             start,
1980             buf.len() as jsize,
1981             buf.as_mut_ptr()
1982         );
1983         Ok(())
1984     }
1985 
1986     /// Copy elements of the java float array from the `start` index to the
1987     /// `buf` slice. The number of copied elements is equal to the `buf` length.
1988     ///
1989     /// # Errors
1990     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
1991     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
1992     /// and `Err` is returned.
1993     ///
1994     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_float_array_region<'other_local>( &self, array: impl AsRef<JFloatArray<'other_local>>, start: jsize, buf: &mut [jfloat], ) -> Result<()>1995     pub fn get_float_array_region<'other_local>(
1996         &self,
1997         array: impl AsRef<JFloatArray<'other_local>>,
1998         start: jsize,
1999         buf: &mut [jfloat],
2000     ) -> Result<()> {
2001         non_null!(array.as_ref(), "get_float_array_region array argument");
2002         jni_void_call!(
2003             self.internal,
2004             GetFloatArrayRegion,
2005             array.as_ref().as_raw(),
2006             start,
2007             buf.len() as jsize,
2008             buf.as_mut_ptr()
2009         );
2010         Ok(())
2011     }
2012 
2013     /// Copy elements of the java double array from the `start` index to the
2014     /// `buf` slice. The number of copied elements is equal to the `buf` length.
2015     ///
2016     /// # Errors
2017     /// If `start` is negative _or_ `start + buf.len()` is greater than [`array.length`]
2018     /// then no elements are copied, an `ArrayIndexOutOfBoundsException` is thrown,
2019     /// and `Err` is returned.
2020     ///
2021     /// [`array.length`]: struct.JNIEnv.html#method.get_array_length
get_double_array_region<'other_local>( &self, array: impl AsRef<JDoubleArray<'other_local>>, start: jsize, buf: &mut [jdouble], ) -> Result<()>2022     pub fn get_double_array_region<'other_local>(
2023         &self,
2024         array: impl AsRef<JDoubleArray<'other_local>>,
2025         start: jsize,
2026         buf: &mut [jdouble],
2027     ) -> Result<()> {
2028         non_null!(array.as_ref(), "get_double_array_region array argument");
2029         jni_void_call!(
2030             self.internal,
2031             GetDoubleArrayRegion,
2032             array.as_ref().as_raw(),
2033             start,
2034             buf.len() as jsize,
2035             buf.as_mut_ptr()
2036         );
2037         Ok(())
2038     }
2039 
2040     /// Copy the contents of the `buf` slice to the java boolean array at the
2041     /// `start` index.
set_boolean_array_region<'other_local>( &self, array: impl AsRef<JBooleanArray<'other_local>>, start: jsize, buf: &[jboolean], ) -> Result<()>2042     pub fn set_boolean_array_region<'other_local>(
2043         &self,
2044         array: impl AsRef<JBooleanArray<'other_local>>,
2045         start: jsize,
2046         buf: &[jboolean],
2047     ) -> Result<()> {
2048         non_null!(array.as_ref(), "set_boolean_array_region array argument");
2049         jni_void_call!(
2050             self.internal,
2051             SetBooleanArrayRegion,
2052             array.as_ref().as_raw(),
2053             start,
2054             buf.len() as jsize,
2055             buf.as_ptr()
2056         );
2057         Ok(())
2058     }
2059 
2060     /// Copy the contents of the `buf` slice to the java byte array at the
2061     /// `start` index.
set_byte_array_region<'other_local>( &self, array: impl AsRef<JByteArray<'other_local>>, start: jsize, buf: &[jbyte], ) -> Result<()>2062     pub fn set_byte_array_region<'other_local>(
2063         &self,
2064         array: impl AsRef<JByteArray<'other_local>>,
2065         start: jsize,
2066         buf: &[jbyte],
2067     ) -> Result<()> {
2068         non_null!(array.as_ref(), "set_byte_array_region array argument");
2069         jni_void_call!(
2070             self.internal,
2071             SetByteArrayRegion,
2072             array.as_ref().as_raw(),
2073             start,
2074             buf.len() as jsize,
2075             buf.as_ptr()
2076         );
2077         Ok(())
2078     }
2079 
2080     /// Copy the contents of the `buf` slice to the java char array at the
2081     /// `start` index.
set_char_array_region<'other_local>( &self, array: impl AsRef<JCharArray<'other_local>>, start: jsize, buf: &[jchar], ) -> Result<()>2082     pub fn set_char_array_region<'other_local>(
2083         &self,
2084         array: impl AsRef<JCharArray<'other_local>>,
2085         start: jsize,
2086         buf: &[jchar],
2087     ) -> Result<()> {
2088         non_null!(array.as_ref(), "set_char_array_region array argument");
2089         jni_void_call!(
2090             self.internal,
2091             SetCharArrayRegion,
2092             array.as_ref().as_raw(),
2093             start,
2094             buf.len() as jsize,
2095             buf.as_ptr()
2096         );
2097         Ok(())
2098     }
2099 
2100     /// Copy the contents of the `buf` slice to the java short array at the
2101     /// `start` index.
set_short_array_region<'other_local>( &self, array: impl AsRef<JShortArray<'other_local>>, start: jsize, buf: &[jshort], ) -> Result<()>2102     pub fn set_short_array_region<'other_local>(
2103         &self,
2104         array: impl AsRef<JShortArray<'other_local>>,
2105         start: jsize,
2106         buf: &[jshort],
2107     ) -> Result<()> {
2108         non_null!(array.as_ref(), "set_short_array_region array argument");
2109         jni_void_call!(
2110             self.internal,
2111             SetShortArrayRegion,
2112             array.as_ref().as_raw(),
2113             start,
2114             buf.len() as jsize,
2115             buf.as_ptr()
2116         );
2117         Ok(())
2118     }
2119 
2120     /// Copy the contents of the `buf` slice to the java int array at the
2121     /// `start` index.
set_int_array_region<'other_local>( &self, array: impl AsRef<JIntArray<'other_local>>, start: jsize, buf: &[jint], ) -> Result<()>2122     pub fn set_int_array_region<'other_local>(
2123         &self,
2124         array: impl AsRef<JIntArray<'other_local>>,
2125         start: jsize,
2126         buf: &[jint],
2127     ) -> Result<()> {
2128         non_null!(array.as_ref(), "set_int_array_region array argument");
2129         jni_void_call!(
2130             self.internal,
2131             SetIntArrayRegion,
2132             array.as_ref().as_raw(),
2133             start,
2134             buf.len() as jsize,
2135             buf.as_ptr()
2136         );
2137         Ok(())
2138     }
2139 
2140     /// Copy the contents of the `buf` slice to the java long array at the
2141     /// `start` index.
set_long_array_region<'other_local>( &self, array: impl AsRef<JLongArray<'other_local>>, start: jsize, buf: &[jlong], ) -> Result<()>2142     pub fn set_long_array_region<'other_local>(
2143         &self,
2144         array: impl AsRef<JLongArray<'other_local>>,
2145         start: jsize,
2146         buf: &[jlong],
2147     ) -> Result<()> {
2148         non_null!(array.as_ref(), "set_long_array_region array argument");
2149         jni_void_call!(
2150             self.internal,
2151             SetLongArrayRegion,
2152             array.as_ref().as_raw(),
2153             start,
2154             buf.len() as jsize,
2155             buf.as_ptr()
2156         );
2157         Ok(())
2158     }
2159 
2160     /// Copy the contents of the `buf` slice to the java float array at the
2161     /// `start` index.
set_float_array_region<'other_local>( &self, array: impl AsRef<JFloatArray<'other_local>>, start: jsize, buf: &[jfloat], ) -> Result<()>2162     pub fn set_float_array_region<'other_local>(
2163         &self,
2164         array: impl AsRef<JFloatArray<'other_local>>,
2165         start: jsize,
2166         buf: &[jfloat],
2167     ) -> Result<()> {
2168         non_null!(array.as_ref(), "set_float_array_region array argument");
2169         jni_void_call!(
2170             self.internal,
2171             SetFloatArrayRegion,
2172             array.as_ref().as_raw(),
2173             start,
2174             buf.len() as jsize,
2175             buf.as_ptr()
2176         );
2177         Ok(())
2178     }
2179 
2180     /// Copy the contents of the `buf` slice to the java double array at the
2181     /// `start` index.
set_double_array_region<'other_local>( &self, array: impl AsRef<JDoubleArray<'other_local>>, start: jsize, buf: &[jdouble], ) -> Result<()>2182     pub fn set_double_array_region<'other_local>(
2183         &self,
2184         array: impl AsRef<JDoubleArray<'other_local>>,
2185         start: jsize,
2186         buf: &[jdouble],
2187     ) -> Result<()> {
2188         non_null!(array.as_ref(), "set_double_array_region array argument");
2189         jni_void_call!(
2190             self.internal,
2191             SetDoubleArrayRegion,
2192             array.as_ref().as_raw(),
2193             start,
2194             buf.len() as jsize,
2195             buf.as_ptr()
2196         );
2197         Ok(())
2198     }
2199 
2200     /// Get a field without checking the provided type against the actual field.
get_field_unchecked<'other_local, O, T>( &mut self, obj: O, field: T, ty: ReturnType, ) -> Result<JValueOwned<'local>> where O: AsRef<JObject<'other_local>>, T: Desc<'local, JFieldID>,2201     pub fn get_field_unchecked<'other_local, O, T>(
2202         &mut self,
2203         obj: O,
2204         field: T,
2205         ty: ReturnType,
2206     ) -> Result<JValueOwned<'local>>
2207     where
2208         O: AsRef<JObject<'other_local>>,
2209         T: Desc<'local, JFieldID>,
2210     {
2211         let obj = obj.as_ref();
2212         non_null!(obj, "get_field_typed obj argument");
2213 
2214         let field = field.lookup(self)?.as_ref().into_raw();
2215         let obj = obj.as_raw();
2216 
2217         // TODO clean this up
2218         Ok(match ty {
2219             ReturnType::Object | ReturnType::Array => {
2220                 let obj = jni_non_void_call!(self.internal, GetObjectField, obj, field);
2221                 let obj = unsafe { JObject::from_raw(obj) };
2222                 obj.into()
2223             }
2224             ReturnType::Primitive(p) => match p {
2225                 Primitive::Boolean => {
2226                     jni_unchecked!(self.internal, GetBooleanField, obj, field).into()
2227                 }
2228                 Primitive::Char => jni_unchecked!(self.internal, GetCharField, obj, field).into(),
2229                 Primitive::Short => jni_unchecked!(self.internal, GetShortField, obj, field).into(),
2230                 Primitive::Int => jni_unchecked!(self.internal, GetIntField, obj, field).into(),
2231                 Primitive::Long => jni_unchecked!(self.internal, GetLongField, obj, field).into(),
2232                 Primitive::Float => jni_unchecked!(self.internal, GetFloatField, obj, field).into(),
2233                 Primitive::Double => {
2234                     jni_unchecked!(self.internal, GetDoubleField, obj, field).into()
2235                 }
2236                 Primitive::Byte => jni_unchecked!(self.internal, GetByteField, obj, field).into(),
2237                 Primitive::Void => {
2238                     return Err(Error::WrongJValueType("void", "see java field"));
2239                 }
2240             },
2241         })
2242     }
2243 
2244     /// Set a field without any type checking.
set_field_unchecked<'other_local, O, T>( &mut self, obj: O, field: T, val: JValue, ) -> Result<()> where O: AsRef<JObject<'other_local>>, T: Desc<'local, JFieldID>,2245     pub fn set_field_unchecked<'other_local, O, T>(
2246         &mut self,
2247         obj: O,
2248         field: T,
2249         val: JValue,
2250     ) -> Result<()>
2251     where
2252         O: AsRef<JObject<'other_local>>,
2253         T: Desc<'local, JFieldID>,
2254     {
2255         let obj = obj.as_ref();
2256         non_null!(obj, "set_field_typed obj argument");
2257 
2258         let field = field.lookup(self)?.as_ref().into_raw();
2259         let obj = obj.as_raw();
2260 
2261         // TODO clean this up
2262         match val {
2263             JValue::Object(o) => {
2264                 jni_unchecked!(self.internal, SetObjectField, obj, field, o.as_raw());
2265             }
2266             // JavaType::Object
2267             JValue::Bool(b) => {
2268                 jni_unchecked!(self.internal, SetBooleanField, obj, field, b);
2269             }
2270             JValue::Char(c) => {
2271                 jni_unchecked!(self.internal, SetCharField, obj, field, c);
2272             }
2273             JValue::Short(s) => {
2274                 jni_unchecked!(self.internal, SetShortField, obj, field, s);
2275             }
2276             JValue::Int(i) => {
2277                 jni_unchecked!(self.internal, SetIntField, obj, field, i);
2278             }
2279             JValue::Long(l) => {
2280                 jni_unchecked!(self.internal, SetLongField, obj, field, l);
2281             }
2282             JValue::Float(f) => {
2283                 jni_unchecked!(self.internal, SetFloatField, obj, field, f);
2284             }
2285             JValue::Double(d) => {
2286                 jni_unchecked!(self.internal, SetDoubleField, obj, field, d);
2287             }
2288             JValue::Byte(b) => {
2289                 jni_unchecked!(self.internal, SetByteField, obj, field, b);
2290             }
2291             JValue::Void => {
2292                 return Err(Error::WrongJValueType("void", "see java field"));
2293             }
2294         };
2295 
2296         Ok(())
2297     }
2298 
2299     /// Get a field. Requires an object class lookup and a field id lookup
2300     /// internally.
get_field<'other_local, O, S, T>( &mut self, obj: O, name: S, ty: T, ) -> Result<JValueOwned<'local>> where O: AsRef<JObject<'other_local>>, S: Into<JNIString>, T: Into<JNIString> + AsRef<str>,2301     pub fn get_field<'other_local, O, S, T>(
2302         &mut self,
2303         obj: O,
2304         name: S,
2305         ty: T,
2306     ) -> Result<JValueOwned<'local>>
2307     where
2308         O: AsRef<JObject<'other_local>>,
2309         S: Into<JNIString>,
2310         T: Into<JNIString> + AsRef<str>,
2311     {
2312         let obj = obj.as_ref();
2313         let class = self.auto_local(self.get_object_class(obj)?);
2314 
2315         let parsed = ReturnType::from_str(ty.as_ref())?;
2316 
2317         let field_id: JFieldID = Desc::<JFieldID>::lookup((&class, name, ty), self)?;
2318 
2319         self.get_field_unchecked(obj, field_id, parsed)
2320     }
2321 
2322     /// Set a field. Does the same lookups as `get_field` and ensures that the
2323     /// type matches the given value.
set_field<'other_local, O, S, T>( &mut self, obj: O, name: S, ty: T, val: JValue, ) -> Result<()> where O: AsRef<JObject<'other_local>>, S: Into<JNIString>, T: Into<JNIString> + AsRef<str>,2324     pub fn set_field<'other_local, O, S, T>(
2325         &mut self,
2326         obj: O,
2327         name: S,
2328         ty: T,
2329         val: JValue,
2330     ) -> Result<()>
2331     where
2332         O: AsRef<JObject<'other_local>>,
2333         S: Into<JNIString>,
2334         T: Into<JNIString> + AsRef<str>,
2335     {
2336         let obj = obj.as_ref();
2337         let parsed = JavaType::from_str(ty.as_ref())?;
2338         let in_type = val.primitive_type();
2339 
2340         match parsed {
2341             JavaType::Object(_) | JavaType::Array(_) => {
2342                 if in_type.is_some() {
2343                     return Err(Error::WrongJValueType(val.type_name(), "see java field"));
2344                 }
2345             }
2346             JavaType::Primitive(p) => {
2347                 if let Some(in_p) = in_type {
2348                     if in_p == p {
2349                         // good
2350                     } else {
2351                         return Err(Error::WrongJValueType(val.type_name(), "see java field"));
2352                     }
2353                 } else {
2354                     return Err(Error::WrongJValueType(val.type_name(), "see java field"));
2355                 }
2356             }
2357             JavaType::Method(_) => unimplemented!(),
2358         }
2359 
2360         let class = self.auto_local(self.get_object_class(obj)?);
2361 
2362         self.set_field_unchecked(obj, (&class, name, ty), val)
2363     }
2364 
2365     /// Get a static field without checking the provided type against the actual
2366     /// field.
get_static_field_unchecked<'other_local, T, U>( &mut self, class: T, field: U, ty: JavaType, ) -> Result<JValueOwned<'local>> where T: Desc<'local, JClass<'other_local>>, U: Desc<'local, JStaticFieldID>,2367     pub fn get_static_field_unchecked<'other_local, T, U>(
2368         &mut self,
2369         class: T,
2370         field: U,
2371         ty: JavaType,
2372     ) -> Result<JValueOwned<'local>>
2373     where
2374         T: Desc<'local, JClass<'other_local>>,
2375         U: Desc<'local, JStaticFieldID>,
2376     {
2377         use JavaType::Primitive as JP;
2378 
2379         let class = class.lookup(self)?;
2380         let field = field.lookup(self)?;
2381 
2382         let result = match ty {
2383             JavaType::Object(_) | JavaType::Array(_) => {
2384                 let obj = jni_non_void_call!(
2385                     self.internal,
2386                     GetStaticObjectField,
2387                     class.as_ref().as_raw(),
2388                     field.as_ref().into_raw()
2389                 );
2390                 let obj = unsafe { JObject::from_raw(obj) };
2391                 obj.into()
2392             }
2393             JavaType::Method(_) => return Err(Error::WrongJValueType("Method", "see java field")),
2394             JP(Primitive::Boolean) => jni_unchecked!(
2395                 self.internal,
2396                 GetStaticBooleanField,
2397                 class.as_ref().as_raw(),
2398                 field.as_ref().into_raw()
2399             )
2400             .into(),
2401             JP(Primitive::Char) => jni_unchecked!(
2402                 self.internal,
2403                 GetStaticCharField,
2404                 class.as_ref().as_raw(),
2405                 field.as_ref().into_raw()
2406             )
2407             .into(),
2408             JP(Primitive::Short) => jni_unchecked!(
2409                 self.internal,
2410                 GetStaticShortField,
2411                 class.as_ref().as_raw(),
2412                 field.as_ref().into_raw()
2413             )
2414             .into(),
2415             JP(Primitive::Int) => jni_unchecked!(
2416                 self.internal,
2417                 GetStaticIntField,
2418                 class.as_ref().as_raw(),
2419                 field.as_ref().into_raw()
2420             )
2421             .into(),
2422             JP(Primitive::Long) => jni_unchecked!(
2423                 self.internal,
2424                 GetStaticLongField,
2425                 class.as_ref().as_raw(),
2426                 field.as_ref().into_raw()
2427             )
2428             .into(),
2429             JP(Primitive::Float) => jni_unchecked!(
2430                 self.internal,
2431                 GetStaticFloatField,
2432                 class.as_ref().as_raw(),
2433                 field.as_ref().into_raw()
2434             )
2435             .into(),
2436             JP(Primitive::Double) => jni_unchecked!(
2437                 self.internal,
2438                 GetStaticDoubleField,
2439                 class.as_ref().as_raw(),
2440                 field.as_ref().into_raw()
2441             )
2442             .into(),
2443             JP(Primitive::Byte) => jni_unchecked!(
2444                 self.internal,
2445                 GetStaticByteField,
2446                 class.as_ref().as_raw(),
2447                 field.as_ref().into_raw()
2448             )
2449             .into(),
2450             JP(Primitive::Void) => return Err(Error::WrongJValueType("void", "see java field")),
2451         };
2452 
2453         // Ensure that `class` isn't dropped before the JNI call returns.
2454         drop(class);
2455 
2456         Ok(result)
2457     }
2458 
2459     /// Get a static field. Requires a class lookup and a field id lookup
2460     /// internally.
get_static_field<'other_local, T, U, V>( &mut self, class: T, field: U, sig: V, ) -> Result<JValueOwned<'local>> where T: Desc<'local, JClass<'other_local>>, U: Into<JNIString>, V: Into<JNIString> + AsRef<str>,2461     pub fn get_static_field<'other_local, T, U, V>(
2462         &mut self,
2463         class: T,
2464         field: U,
2465         sig: V,
2466     ) -> Result<JValueOwned<'local>>
2467     where
2468         T: Desc<'local, JClass<'other_local>>,
2469         U: Into<JNIString>,
2470         V: Into<JNIString> + AsRef<str>,
2471     {
2472         let ty = JavaType::from_str(sig.as_ref())?;
2473 
2474         // go ahead and look up the class sincewe'll need that for the next
2475         // call.
2476         let class = class.lookup(self)?;
2477 
2478         self.get_static_field_unchecked(class.as_ref(), (class.as_ref(), field, sig), ty)
2479     }
2480 
2481     /// Set a static field. Requires a class lookup and a field id lookup internally.
set_static_field<'other_local, T, U>( &mut self, class: T, field: U, value: JValue, ) -> Result<()> where T: Desc<'local, JClass<'other_local>>, U: Desc<'local, JStaticFieldID>,2482     pub fn set_static_field<'other_local, T, U>(
2483         &mut self,
2484         class: T,
2485         field: U,
2486         value: JValue,
2487     ) -> Result<()>
2488     where
2489         T: Desc<'local, JClass<'other_local>>,
2490         U: Desc<'local, JStaticFieldID>,
2491     {
2492         let class = class.lookup(self)?;
2493         let field = field.lookup(self)?;
2494 
2495         match value {
2496             JValue::Object(v) => jni_unchecked!(
2497                 self.internal,
2498                 SetStaticObjectField,
2499                 class.as_ref().as_raw(),
2500                 field.as_ref().into_raw(),
2501                 v.as_raw()
2502             ),
2503             JValue::Byte(v) => jni_unchecked!(
2504                 self.internal,
2505                 SetStaticByteField,
2506                 class.as_ref().as_raw(),
2507                 field.as_ref().into_raw(),
2508                 v
2509             ),
2510             JValue::Char(v) => jni_unchecked!(
2511                 self.internal,
2512                 SetStaticCharField,
2513                 class.as_ref().as_raw(),
2514                 field.as_ref().into_raw(),
2515                 v
2516             ),
2517             JValue::Short(v) => jni_unchecked!(
2518                 self.internal,
2519                 SetStaticShortField,
2520                 class.as_ref().as_raw(),
2521                 field.as_ref().into_raw(),
2522                 v
2523             ),
2524             JValue::Int(v) => jni_unchecked!(
2525                 self.internal,
2526                 SetStaticIntField,
2527                 class.as_ref().as_raw(),
2528                 field.as_ref().into_raw(),
2529                 v
2530             ),
2531             JValue::Long(v) => jni_unchecked!(
2532                 self.internal,
2533                 SetStaticLongField,
2534                 class.as_ref().as_raw(),
2535                 field.as_ref().into_raw(),
2536                 v
2537             ),
2538             JValue::Bool(v) => {
2539                 jni_unchecked!(
2540                     self.internal,
2541                     SetStaticBooleanField,
2542                     class.as_ref().as_raw(),
2543                     field.as_ref().into_raw(),
2544                     v
2545                 )
2546             }
2547             JValue::Float(v) => jni_unchecked!(
2548                 self.internal,
2549                 SetStaticFloatField,
2550                 class.as_ref().as_raw(),
2551                 field.as_ref().into_raw(),
2552                 v
2553             ),
2554             JValue::Double(v) => {
2555                 jni_unchecked!(
2556                     self.internal,
2557                     SetStaticDoubleField,
2558                     class.as_ref().as_raw(),
2559                     field.as_ref().into_raw(),
2560                     v
2561                 )
2562             }
2563             JValue::Void => return Err(Error::WrongJValueType("void", "?")),
2564         }
2565 
2566         // Ensure that `class` isn't dropped before the JNI call returns.
2567         drop(class);
2568 
2569         Ok(())
2570     }
2571 
2572     /// Surrenders ownership of a Rust value to Java.
2573     ///
2574     /// This requires an object with a `long` field to store the pointer.
2575     ///
2576     /// In Java the property may look like:
2577     /// ```java
2578     /// private long myRustValueHandle = 0;
2579     /// ```
2580     ///
2581     /// Or, in Kotlin the property may look like:
2582     /// ```java
2583     /// private var myRustValueHandle: Long = 0
2584     /// ```
2585     ///
2586     /// _Note that `private` properties are accessible to JNI which may be
2587     /// preferable to avoid exposing the handles to more code than necessary
2588     /// (since the handles are usually only meaningful to Rust code)_.
2589     ///
2590     /// The Rust value will be implicitly wrapped in a `Box<Mutex<T>>`.
2591     ///
2592     /// The Java object will be locked while changing the field value.
2593     ///
2594     /// # Safety
2595     ///
2596     /// It's important to note that using this API will leak memory if
2597     /// [`Self::take_rust_field`] is never called so that the Rust type may be
2598     /// dropped.
2599     ///
2600     /// One suggestion that may help ensure that a set Rust field will be
2601     /// cleaned up later is for the Java object to implement `Closeable` and let
2602     /// people use a `use` block (Kotlin) or `try-with-resources` (Java).
2603     ///
2604     /// **DO NOT** make a copy of the handle stored in one of these fields
2605     /// since that could lead to a use-after-free error if the Rust type is
2606     /// taken and dropped multiple times from Rust. If you need to copy an
2607     /// object with one of these fields then the field should be zero
2608     /// initialized in the copy.
2609     #[allow(unused_variables)]
set_rust_field<'other_local, O, S, T>( &mut self, obj: O, field: S, rust_object: T, ) -> Result<()> where O: AsRef<JObject<'other_local>>, S: AsRef<str>, T: Send + 'static,2610     pub unsafe fn set_rust_field<'other_local, O, S, T>(
2611         &mut self,
2612         obj: O,
2613         field: S,
2614         rust_object: T,
2615     ) -> Result<()>
2616     where
2617         O: AsRef<JObject<'other_local>>,
2618         S: AsRef<str>,
2619         T: Send + 'static,
2620     {
2621         let obj = obj.as_ref();
2622         let class = self.auto_local(self.get_object_class(obj)?);
2623         let field_id: JFieldID = Desc::<JFieldID>::lookup((&class, &field, "J"), self)?;
2624 
2625         let guard = self.lock_obj(obj)?;
2626 
2627         // Check to see if we've already set this value. If it's not null, that
2628         // means that we're going to leak memory if it gets overwritten.
2629         let field_ptr = self
2630             .get_field_unchecked(obj, field_id, ReturnType::Primitive(Primitive::Long))?
2631             .j()? as *mut Mutex<T>;
2632         if !field_ptr.is_null() {
2633             return Err(Error::FieldAlreadySet(field.as_ref().to_owned()));
2634         }
2635 
2636         let mbox = Box::new(::std::sync::Mutex::new(rust_object));
2637         let ptr: *mut Mutex<T> = Box::into_raw(mbox);
2638 
2639         self.set_field_unchecked(obj, field_id, (ptr as crate::sys::jlong).into())
2640     }
2641 
2642     /// Gets a lock on a Rust value that's been given to a Java object.
2643     ///
2644     /// Java still retains ownership and [`Self::take_rust_field`] will still
2645     /// need to be called at some point.
2646     ///
2647     /// The Java object will be locked before reading the field value but the
2648     /// Java object lock will be released after the Rust `Mutex` lock for the
2649     /// field value has been taken (i.e the Java object won't be locked once
2650     /// this function returns).
2651     ///
2652     /// # Safety
2653     ///
2654     /// Checks for a null pointer, but assumes that the data it points to is valid for T.
2655     #[allow(unused_variables)]
get_rust_field<'other_local, O, S, T>( &mut self, obj: O, field: S, ) -> Result<MutexGuard<T>> where O: AsRef<JObject<'other_local>>, S: Into<JNIString>, T: Send + 'static,2656     pub unsafe fn get_rust_field<'other_local, O, S, T>(
2657         &mut self,
2658         obj: O,
2659         field: S,
2660     ) -> Result<MutexGuard<T>>
2661     where
2662         O: AsRef<JObject<'other_local>>,
2663         S: Into<JNIString>,
2664         T: Send + 'static,
2665     {
2666         let obj = obj.as_ref();
2667         let guard = self.lock_obj(obj)?;
2668 
2669         let ptr = self.get_field(obj, field, "J")?.j()? as *mut Mutex<T>;
2670         non_null!(ptr, "rust value from Java");
2671         // dereferencing is safe, because we checked it for null
2672         Ok((*ptr).lock().unwrap())
2673     }
2674 
2675     /// Take a Rust field back from Java.
2676     ///
2677     /// It sets the field to a null pointer to signal that it's empty.
2678     ///
2679     /// The Java object will be locked before taking the field value.
2680     ///
2681     /// # Safety
2682     ///
2683     /// This will make sure that the pointer is non-null, but still assumes that
2684     /// the data it points to is valid for T.
2685     #[allow(unused_variables)]
take_rust_field<'other_local, O, S, T>(&mut self, obj: O, field: S) -> Result<T> where O: AsRef<JObject<'other_local>>, S: AsRef<str>, T: Send + 'static,2686     pub unsafe fn take_rust_field<'other_local, O, S, T>(&mut self, obj: O, field: S) -> Result<T>
2687     where
2688         O: AsRef<JObject<'other_local>>,
2689         S: AsRef<str>,
2690         T: Send + 'static,
2691     {
2692         let obj = obj.as_ref();
2693         let class = self.auto_local(self.get_object_class(obj)?);
2694         let field_id: JFieldID = Desc::<JFieldID>::lookup((&class, &field, "J"), self)?;
2695 
2696         let mbox = {
2697             let guard = self.lock_obj(obj)?;
2698 
2699             let ptr = self
2700                 .get_field_unchecked(obj, field_id, ReturnType::Primitive(Primitive::Long))?
2701                 .j()? as *mut Mutex<T>;
2702 
2703             non_null!(ptr, "rust value from Java");
2704 
2705             let mbox = Box::from_raw(ptr);
2706 
2707             // attempt to acquire the lock. This prevents us from consuming the
2708             // mutex if there's an outstanding lock. No one else will be able to
2709             // get a new one as long as we're in the guarded scope.
2710             drop(mbox.try_lock()?);
2711 
2712             self.set_field_unchecked(
2713                 obj,
2714                 field_id,
2715                 (::std::ptr::null_mut::<()>() as sys::jlong).into(),
2716             )?;
2717 
2718             mbox
2719         };
2720 
2721         Ok(mbox.into_inner().unwrap())
2722     }
2723 
2724     /// Lock a Java object. The MonitorGuard that this returns is responsible
2725     /// for ensuring that it gets unlocked.
lock_obj<'other_local, O>(&self, obj: O) -> Result<MonitorGuard<'local>> where O: AsRef<JObject<'other_local>>,2726     pub fn lock_obj<'other_local, O>(&self, obj: O) -> Result<MonitorGuard<'local>>
2727     where
2728         O: AsRef<JObject<'other_local>>,
2729     {
2730         let inner = obj.as_ref().as_raw();
2731         let _ = jni_unchecked!(self.internal, MonitorEnter, inner);
2732 
2733         Ok(MonitorGuard {
2734             obj: inner,
2735             env: self.internal,
2736             life: Default::default(),
2737         })
2738     }
2739 
2740     /// Returns underlying `sys::JNIEnv` interface.
get_native_interface(&self) -> *mut sys::JNIEnv2741     pub fn get_native_interface(&self) -> *mut sys::JNIEnv {
2742         self.internal
2743     }
2744 
2745     /// Returns the Java VM interface.
get_java_vm(&self) -> Result<JavaVM>2746     pub fn get_java_vm(&self) -> Result<JavaVM> {
2747         let mut raw = ptr::null_mut();
2748         let res = jni_unchecked!(self.internal, GetJavaVM, &mut raw);
2749         jni_error_code_to_result(res)?;
2750         unsafe { JavaVM::from_raw(raw) }
2751     }
2752 
2753     /// Ensures that at least a given number of local references can be created
2754     /// in the current thread.
ensure_local_capacity(&self, capacity: jint) -> Result<()>2755     pub fn ensure_local_capacity(&self, capacity: jint) -> Result<()> {
2756         jni_void_call!(self.internal, EnsureLocalCapacity, capacity);
2757         Ok(())
2758     }
2759 
2760     /// Bind function pointers to native methods of class
2761     /// according to method name and signature.
2762     /// For details see [documentation](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#RegisterNatives).
register_native_methods<'other_local, T>( &mut self, class: T, methods: &[NativeMethod], ) -> Result<()> where T: Desc<'local, JClass<'other_local>>,2763     pub fn register_native_methods<'other_local, T>(
2764         &mut self,
2765         class: T,
2766         methods: &[NativeMethod],
2767     ) -> Result<()>
2768     where
2769         T: Desc<'local, JClass<'other_local>>,
2770     {
2771         let class = class.lookup(self)?;
2772         let jni_native_methods: Vec<JNINativeMethod> = methods
2773             .iter()
2774             .map(|nm| JNINativeMethod {
2775                 name: nm.name.as_ptr() as *mut c_char,
2776                 signature: nm.sig.as_ptr() as *mut c_char,
2777                 fnPtr: nm.fn_ptr,
2778             })
2779             .collect();
2780         let res = jni_non_void_call!(
2781             self.internal,
2782             RegisterNatives,
2783             class.as_ref().as_raw(),
2784             jni_native_methods.as_ptr(),
2785             jni_native_methods.len() as jint
2786         );
2787 
2788         // Ensure that `class` isn't dropped before the JNI call returns.
2789         drop(class);
2790 
2791         jni_error_code_to_result(res)
2792     }
2793 
2794     /// Unbind all native methods of class.
unregister_native_methods<'other_local, T>(&mut self, class: T) -> Result<()> where T: Desc<'local, JClass<'other_local>>,2795     pub fn unregister_native_methods<'other_local, T>(&mut self, class: T) -> Result<()>
2796     where
2797         T: Desc<'local, JClass<'other_local>>,
2798     {
2799         let class = class.lookup(self)?;
2800         let res = jni_non_void_call!(self.internal, UnregisterNatives, class.as_ref().as_raw());
2801 
2802         // Ensure that `class` isn't dropped before the JNI call returns.
2803         drop(class);
2804 
2805         jni_error_code_to_result(res)
2806     }
2807 
2808     /// Returns an [`AutoElements`] to access the elements of the given Java `array`.
2809     ///
2810     /// The elements are accessible until the returned auto-release guard is dropped.
2811     ///
2812     /// The returned array may be a copy of the Java array and changes made to
2813     /// the returned array will not necessarily be reflected in the original
2814     /// array until the [`AutoElements`] guard is dropped.
2815     ///
2816     /// If you know in advance that you will only be reading from the array then
2817     /// pass [`ReleaseMode::NoCopyBack`] so that the JNI implementation knows
2818     /// that it's not necessary to copy any data back to the original Java array
2819     /// when the [`AutoElements`] guard is dropped.
2820     ///
2821     /// Since the returned array may be a copy of the Java array, changes made to the
2822     /// returned array will not necessarily be reflected in the original array until
2823     /// the corresponding `Release*ArrayElements` JNI method is called.
2824     /// [`AutoElements`] has a commit() method, to force a copy back of pending
2825     /// array changes if needed (and without releasing it).
2826     ///
2827     /// # Safety
2828     ///
2829     /// ## No data races
2830     ///
2831     /// This API has no built-in synchronization that ensures there won't be any data
2832     /// races while accessing the array elements.
2833     ///
2834     /// To avoid undefined behaviour it is the caller's responsibility to ensure there
2835     /// will be no data races between other Rust or Java threads trying to access the
2836     /// same array.
2837     ///
2838     /// Acquiring a [`MonitorGuard`] lock for the `array` could be one way of ensuring
2839     /// mutual exclusion between Rust and Java threads, so long as the Java threads
2840     /// also acquire the same lock via `synchronized(array) {}`.
2841     ///
2842     /// ## No aliasing
2843     ///
2844     /// Callers must not create more than one [`AutoElements`] or
2845     /// [`AutoElementsCritical`] per Java array at the same time - even if
2846     /// there is no risk of a data race.
2847     ///
2848     /// The reason for this restriction is that [`AutoElements`] and
2849     /// [`AutoElementsCritical`] implement `DerefMut` which can provide a
2850     /// mutable `&mut [T]` slice reference for the elements and it would
2851     /// constitute undefined behaviour to allow there to be more than one
2852     /// mutable reference that points to the same memory.
2853     ///
2854     /// # jboolean elements
2855     ///
2856     /// Keep in mind that arrays of `jboolean` values should only ever hold
2857     /// values of `0` or `1` because any other value could lead to undefined
2858     /// behaviour within the JVM.
2859     ///
2860     /// Also see
2861     /// [`get_array_elements_critical`](Self::get_array_elements_critical) which
2862     /// imposes additional restrictions that make it less likely to incur the
2863     /// cost of copying the array elements.
get_array_elements<'other_local, 'array, T: TypeArray>( &mut self, array: &'array JPrimitiveArray<'other_local, T>, mode: ReleaseMode, ) -> Result<AutoElements<'local, 'other_local, 'array, T>>2864     pub unsafe fn get_array_elements<'other_local, 'array, T: TypeArray>(
2865         &mut self,
2866         array: &'array JPrimitiveArray<'other_local, T>,
2867         mode: ReleaseMode,
2868     ) -> Result<AutoElements<'local, 'other_local, 'array, T>> {
2869         non_null!(array, "get_array_elements array argument");
2870         AutoElements::new(self, array, mode)
2871     }
2872 
2873     /// Returns an [`AutoElementsCritical`] to access the elements of the given Java `array`.
2874     ///
2875     /// The elements are accessible during the critical section that exists until the
2876     /// returned auto-release guard is dropped.
2877     ///
2878     /// This API imposes some strict restrictions that help the JNI implementation
2879     /// avoid any need to copy the underlying array elements before making them
2880     /// accessible to native code:
2881     ///
2882     /// 1. No other use of JNI calls are allowed (on the same thread) within the critical
2883     /// section that exists while holding the [`AutoElementsCritical`] guard.
2884     /// 2. No system calls can be made (Such as `read`) that may depend on a result
2885     /// from another Java thread.
2886     ///
2887     /// The JNI spec does not specify what will happen if these rules aren't adhered to
2888     /// but it should be assumed it will lead to undefined behaviour, likely deadlock
2889     /// and possible program termination.
2890     ///
2891     /// Even with these restrictions the returned array may still be a copy of
2892     /// the Java array and changes made to the returned array will not
2893     /// necessarily be reflected in the original array until the [`AutoElementsCritical`]
2894     /// guard is dropped.
2895     ///
2896     /// If you know in advance that you will only be reading from the array then
2897     /// pass [`ReleaseMode::NoCopyBack`] so that the JNI implementation knows
2898     /// that it's not necessary to copy any data back to the original Java array
2899     /// when the [`AutoElementsCritical`] guard is dropped.
2900     ///
2901     /// A nested scope or explicit use of `std::mem::drop` can be used to
2902     /// control when the returned [`AutoElementsCritical`] is dropped to
2903     /// minimize the length of the critical section.
2904     ///
2905     /// If the given array is `null`, an `Error::NullPtr` is returned.
2906     ///
2907     /// # Safety
2908     ///
2909     /// ## Critical Section Restrictions
2910     ///
2911     /// Although this API takes a mutable reference to a [`JNIEnv`] which should
2912     /// ensure that it's not possible to call JNI, this API is still marked as
2913     /// `unsafe` due to the complex, far-reaching nature of the critical-section
2914     /// restrictions imposed here that can't be guaranteed simply through Rust's
2915     /// borrow checker rules.
2916     ///
2917     /// The rules above about JNI usage and system calls _must_ be adhered to.
2918     ///
2919     /// Using this API implies:
2920     ///
2921     /// 1. All garbage collection will likely be paused during the critical section
2922     /// 2. Any use of JNI in other threads may block if they need to allocate memory
2923     ///    (due to the garbage collector being paused)
2924     /// 3. Any use of system calls that will wait for a result from another Java thread
2925     ///    could deadlock if that other thread is blocked by a paused garbage collector.
2926     ///
2927     /// A failure to adhere to the critical section rules could lead to any
2928     /// undefined behaviour, including aborting the program.
2929     ///
2930     /// ## No data races
2931     ///
2932     /// This API has no built-in synchronization that ensures there won't be any data
2933     /// races while accessing the array elements.
2934     ///
2935     /// To avoid undefined behaviour it is the caller's responsibility to ensure there
2936     /// will be no data races between other Rust or Java threads trying to access the
2937     /// same array.
2938     ///
2939     /// Acquiring a [`MonitorGuard`] lock for the `array` could be one way of ensuring
2940     /// mutual exclusion between Rust and Java threads, so long as the Java threads
2941     /// also acquire the same lock via `synchronized(array) {}`.
2942     ///
2943     /// ## No aliasing
2944     ///
2945     /// Callers must not create more than one [`AutoElements`] or
2946     /// [`AutoElementsCritical`] per Java array at the same time - even if
2947     /// there is no risk of a data race.
2948     ///
2949     /// The reason for this restriction is that [`AutoElements`] and
2950     /// [`AutoElementsCritical`] implement `DerefMut` which can provide a
2951     /// mutable `&mut [T]` slice reference for the elements and it would
2952     /// constitute undefined behaviour to allow there to be more than one
2953     /// mutable reference that points to the same memory.
2954     ///
2955     /// ## jboolean elements
2956     ///
2957     /// Keep in mind that arrays of `jboolean` values should only ever hold
2958     /// values of `0` or `1` because any other value could lead to undefined
2959     /// behaviour within the JVM.
2960     ///
2961     /// Also see [`get_array_elements`](Self::get_array_elements) which has fewer
2962     /// restrictions, but is is more likely to incur a cost from copying the
2963     /// array elements.
get_array_elements_critical<'other_local, 'array, 'env, T: TypeArray>( &'env mut self, array: &'array JPrimitiveArray<'other_local, T>, mode: ReleaseMode, ) -> Result<AutoElementsCritical<'local, 'other_local, 'array, 'env, T>>2964     pub unsafe fn get_array_elements_critical<'other_local, 'array, 'env, T: TypeArray>(
2965         &'env mut self,
2966         array: &'array JPrimitiveArray<'other_local, T>,
2967         mode: ReleaseMode,
2968     ) -> Result<AutoElementsCritical<'local, 'other_local, 'array, 'env, T>> {
2969         non_null!(array, "get_primitive_array_critical array argument");
2970         AutoElementsCritical::new(self, array, mode)
2971     }
2972 }
2973 
2974 /// Native method descriptor.
2975 pub struct NativeMethod {
2976     /// Name of method.
2977     pub name: JNIString,
2978     /// Method signature.
2979     pub sig: JNIString,
2980     /// Pointer to native function with signature
2981     /// `fn(env: JNIEnv, class: JClass, ...arguments according to sig) -> RetType`
2982     /// for static methods or
2983     /// `fn(env: JNIEnv, object: JObject, ...arguments according to sig) -> RetType`
2984     /// for instance methods.
2985     pub fn_ptr: *mut c_void,
2986 }
2987 
2988 /// Guard for a lock on a java object. This gets returned from the `lock_obj`
2989 /// method.
2990 pub struct MonitorGuard<'local> {
2991     obj: sys::jobject,
2992     env: *mut sys::JNIEnv,
2993     life: PhantomData<&'local ()>,
2994 }
2995 
2996 impl<'local> Drop for MonitorGuard<'local> {
drop(&mut self)2997     fn drop(&mut self) {
2998         let res: Result<()> = catch!({
2999             jni_unchecked!(self.env, MonitorExit, self.obj);
3000             Ok(())
3001         });
3002 
3003         if let Err(e) = res {
3004             warn!("error releasing java monitor: {}", e)
3005         }
3006     }
3007 }
3008