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