jni/wrapper/
jnienv.rs

1use std::{
2    marker::PhantomData,
3    os::raw::{c_char, c_void},
4    ptr, str,
5    str::FromStr,
6    sync::{Mutex, MutexGuard},
7};
8
9use log::warn;
10
11use 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};
27use crate::{
28    errors::Error::JniCall,
29    objects::{
30        JBooleanArray, JByteArray, JCharArray, JDoubleArray, JFloatArray, JIntArray, JLongArray,
31        JObjectArray, JPrimitiveArray, JShortArray,
32    },
33};
34use 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)]
196pub struct JNIEnv<'local> {
197    internal: *mut sys::JNIEnv,
198    lifetime: PhantomData<&'local ()>,
199}
200
201impl<'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.
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
216    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
233    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.
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.
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.
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`.
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.
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    /// ```
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
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.
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.
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.
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    /// ```
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    /// ```
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.
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.
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.
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)]
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.
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`.
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.
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`).
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.
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.
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
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.).
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.
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.
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.
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`].
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`].
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.
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)]
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    /// ```
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    /// ```
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    /// ```
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    /// ```
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.
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.
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.
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.
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.
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`.
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.
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.
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.
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`
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`
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.
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`].
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
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`.
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`.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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
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
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
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
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
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
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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)]
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)]
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)]
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.
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.
2741    pub fn get_native_interface(&self) -> *mut sys::JNIEnv {
2742        self.internal
2743    }
2744
2745    /// Returns the Java VM interface.
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.
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).
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.
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.
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.
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.
2975pub 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.
2990pub struct MonitorGuard<'local> {
2991    obj: sys::jobject,
2992    env: *mut sys::JNIEnv,
2993    life: PhantomData<&'local ()>,
2994}
2995
2996impl<'local> Drop for MonitorGuard<'local> {
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}