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>&[JObject]</code>
89/// or <code>&[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}