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