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