pub struct AttachGuard<'local> { /* private fields */ }
Expand description
A RAII implementation of scoped guard which detaches the current thread
when dropped. The attached JNIEnv
can be accessed through this guard
via its Deref
implementation.
Methods from Deref<Target = JNIEnv<'local>>§
Sourcepub fn get_raw(&self) -> *mut *const JNINativeInterface_
pub fn get_raw(&self) -> *mut *const JNINativeInterface_
Get the raw JNIEnv pointer
Sourcepub unsafe fn unsafe_clone(&self) -> JNIEnv<'local>
pub unsafe fn unsafe_clone(&self) -> JNIEnv<'local>
Duplicates this JNIEnv
.
§Safety
The duplicate JNIEnv
must not be used to create any local references, unless they are
discarded before the current local reference frame is exited. Otherwise, they may have a
lifetime longer than they are actually valid for, resulting in a use-after-free bug and
undefined behavior.
See issue #392 for background.
Sourcepub fn get_version(&self) -> Result<JNIVersion, Error>
pub fn get_version(&self) -> Result<JNIVersion, Error>
Get the java version that we’re being executed from.
Sourcepub fn define_class<S>(
&mut self,
name: S,
loader: &JObject<'_>,
buf: &[u8],
) -> Result<JClass<'local>, Error>
pub fn define_class<S>( &mut self, name: S, loader: &JObject<'_>, buf: &[u8], ) -> Result<JClass<'local>, Error>
Load a class from a buffer of raw class data. The name of the class must match the name encoded within the class file data.
Sourcepub fn define_unnamed_class(
&mut self,
loader: &JObject<'_>,
buf: &[u8],
) -> Result<JClass<'local>, Error>
pub fn define_unnamed_class( &mut self, loader: &JObject<'_>, buf: &[u8], ) -> Result<JClass<'local>, Error>
Load a class from a buffer of raw class data. The name of the class is inferred from the buffer.
Sourcepub fn define_class_bytearray<S>(
&mut self,
name: S,
loader: &JObject<'_>,
buf: &AutoElements<'_, '_, '_, i8>,
) -> Result<JClass<'local>, Error>
pub fn define_class_bytearray<S>( &mut self, name: S, loader: &JObject<'_>, buf: &AutoElements<'_, '_, '_, i8>, ) -> Result<JClass<'local>, Error>
Load a class from a buffer of raw class data. The name of the class must match the name encoded within the class file data.
Sourcepub fn find_class<S>(&mut self, name: S) -> Result<JClass<'local>, Error>
pub fn find_class<S>(&mut self, name: S) -> Result<JClass<'local>, Error>
Sourcepub fn get_superclass<'other_local, T>(
&mut self,
class: T,
) -> Result<Option<JClass<'local>>, Error>
pub fn get_superclass<'other_local, T>( &mut self, class: T, ) -> Result<Option<JClass<'local>>, Error>
Returns the superclass for a particular class. Returns None for java.lang.Object
or
an interface. As with Self::find_class, takes a descriptor
§Errors
If a JNI call fails
Sourcepub fn is_assignable_from<'other_local_1, 'other_local_2, T, U>(
&mut self,
class1: T,
class2: U,
) -> Result<bool, Error>
pub fn is_assignable_from<'other_local_1, 'other_local_2, T, U>( &mut self, class1: T, class2: U, ) -> Result<bool, Error>
Tests whether class1 is assignable from class2.
Sourcepub fn is_instance_of<'other_local_1, 'other_local_2, O, T>(
&mut self,
object: O,
class: T,
) -> Result<bool, Error>
pub fn is_instance_of<'other_local_1, 'other_local_2, O, T>( &mut self, object: O, class: T, ) -> Result<bool, Error>
Returns true if the object reference can be cast to the given type.
NB: Unlike the operator instanceof
, function IsInstanceOf
returns true
for all classes if object
is null
.
See JNI documentation for details.
Sourcepub fn is_same_object<'other_local_1, 'other_local_2, O, T>(
&self,
ref1: O,
ref2: T,
) -> Result<bool, Error>
pub fn is_same_object<'other_local_1, 'other_local_2, O, T>( &self, ref1: O, ref2: T, ) -> Result<bool, Error>
Returns true if ref1 and ref2 refer to the same Java object, or are both NULL
. Otherwise,
returns false.
Sourcepub fn throw<'other_local, E>(&mut self, obj: E) -> Result<(), Error>where
E: Desc<'local, JThrowable<'other_local>>,
pub fn throw<'other_local, E>(&mut self, obj: E) -> Result<(), Error>where
E: Desc<'local, JThrowable<'other_local>>,
Raise an exception from an existing object. This will continue being
thrown in java unless exception_clear
is called.
§Examples
env.throw(("java/lang/Exception", "something bad happened"))?;
Defaulting to “java/lang/Exception”:
env.throw("something bad happened")?;
Sourcepub fn throw_new<'other_local, S, T>(
&mut self,
class: T,
msg: S,
) -> Result<(), Error>
pub fn throw_new<'other_local, S, T>( &mut self, class: T, msg: S, ) -> Result<(), Error>
Create and throw a new exception from a class descriptor and an error message.
§Example
env.throw_new("java/lang/Exception", "something bad happened")?;
Sourcepub fn exception_occurred(&mut self) -> Result<JThrowable<'local>, Error>
pub fn exception_occurred(&mut self) -> Result<JThrowable<'local>, Error>
Check whether or not an exception is currently in the process of being
thrown. An exception is in this state from the time it gets thrown and
not caught in a java function until exception_clear
is called.
Sourcepub fn exception_describe(&self) -> Result<(), Error>
pub fn exception_describe(&self) -> Result<(), Error>
Print exception information to the console.
Sourcepub fn exception_clear(&self) -> Result<(), Error>
pub fn exception_clear(&self) -> Result<(), Error>
Clear an exception in the process of being thrown. If this is never called, the exception will continue being thrown when control is returned to java.
Sourcepub fn fatal_error<S>(&self, msg: S) -> !
pub fn fatal_error<S>(&self, msg: S) -> !
Abort the JVM with an error message.
Sourcepub fn exception_check(&self) -> Result<bool, Error>
pub fn exception_check(&self) -> Result<bool, Error>
Check to see if an exception is being thrown. This only differs from
exception_occurred
in that it doesn’t return the actual thrown
exception.
Sourcepub unsafe fn new_direct_byte_buffer(
&mut self,
data: *mut u8,
len: usize,
) -> Result<JByteBuffer<'local>, Error>
pub unsafe fn new_direct_byte_buffer( &mut self, data: *mut u8, len: usize, ) -> Result<JByteBuffer<'local>, Error>
Create a new instance of a direct java.nio.ByteBuffer
§Example
let buf = vec![0; 1024 * 1024];
let (addr, len) = { // (use buf.into_raw_parts() on nightly)
let buf = buf.leak();
(buf.as_mut_ptr(), buf.len())
};
let direct_buffer = unsafe { env.new_direct_byte_buffer(addr, len) }?;
§Safety
Expects a valid (non-null) pointer and length
Caller must ensure the lifetime of data
extends to all uses of the returned
ByteBuffer
. The JVM may maintain references to the ByteBuffer
beyond the lifetime
of this JNIEnv
.
Sourcepub fn get_direct_buffer_address(
&self,
buf: &JByteBuffer<'_>,
) -> Result<*mut u8, Error>
pub fn get_direct_buffer_address( &self, buf: &JByteBuffer<'_>, ) -> Result<*mut u8, Error>
Returns the starting address of the memory of the direct java.nio.ByteBuffer.
Sourcepub fn get_direct_buffer_capacity(
&self,
buf: &JByteBuffer<'_>,
) -> Result<usize, Error>
pub fn get_direct_buffer_capacity( &self, buf: &JByteBuffer<'_>, ) -> Result<usize, Error>
Returns the capacity (length) of the direct java.nio.ByteBuffer.
§Terminology
“capacity” here means the length that was passed to Self::new_direct_byte_buffer()
which does not reflect the (potentially) larger size of the underlying allocation (unlike the Vec
API).
The terminology is simply kept from the original JNI API (GetDirectBufferCapacity
).
Sourcepub fn new_global_ref<'other_local, O>(
&self,
obj: O,
) -> Result<GlobalRef, Error>
pub fn new_global_ref<'other_local, O>( &self, obj: O, ) -> Result<GlobalRef, Error>
Turns an object into a global ref. This has the benefit of removing the lifetime bounds since it’s guaranteed to not get GC’d by java. It releases the GC pin upon being dropped.
Sourcepub fn new_weak_ref<'other_local, O>(
&self,
obj: O,
) -> Result<Option<WeakRef>, Error>
pub fn new_weak_ref<'other_local, O>( &self, obj: O, ) -> Result<Option<WeakRef>, Error>
Creates a new weak global reference.
If the provided object is null, this method returns None
. Otherwise, it returns Some
containing the new weak global reference.
Sourcepub fn new_local_ref<'other_local, O>(
&self,
obj: O,
) -> Result<JObject<'local>, Error>
pub fn new_local_ref<'other_local, O>( &self, obj: O, ) -> Result<JObject<'local>, Error>
Create a new local reference to an object.
Specifically, this calls the JNI function NewLocalRef
, which creates a reference in the
current local reference frame, regardless of whether the original reference belongs to the
same local reference frame, a different one, or is a global reference. In Rust
terms, this method accepts a JNI reference with any valid lifetime and produces a clone of
that reference with the lifetime of this JNIEnv
. The returned reference can outlive the
original.
This method is useful when you have a strong global reference and you can’t prevent it from being dropped before you’re finished with it. In that case, you can use this method to create a new local reference that’s guaranteed to remain valid for the duration of the current local reference frame, regardless of what later happens to the original global reference.
§Lifetimes
'local
is the lifetime of the local reference frame that this JNIEnv
belongs to. This
method creates a new local reference in that frame, with lifetime 'local
.
'other_local
is the lifetime of the original reference’s frame. It can be any valid
lifetime, even one that 'local
outlives or vice versa.
Think of 'local
as meaning 'new
and 'other_local
as meaning 'original
. (It is
unfortunately not possible to actually give these names to the two lifetimes because
'local
is a parameter to the JNIEnv
type, not a parameter to this method.)
§Example
In the following example, the ExampleError::extract_throwable
method uses
JNIEnv::new_local_ref
to create a new local reference that outlives the original global
reference:
/// An error that may be caused by either a Java exception or something going wrong in Rust
/// code.
enum ExampleError {
/// This variant represents a Java exception.
///
/// The enclosed `GlobalRef` points to a Java object of class `java.lang.Throwable`
/// (or one of its many subclasses).
Exception(GlobalRef),
/// This variant represents an error in Rust code, not a Java exception.
Other(SomeOtherErrorType),
}
impl ExampleError {
/// Consumes this `ExampleError` and produces a `JThrowable`, suitable for throwing
/// back to Java code.
///
/// If this is an `ExampleError::Exception`, then this extracts the enclosed Java
/// exception object. Otherwise, a new exception object is created to represent this
/// error.
fn extract_throwable<'local>(self, env: &mut JNIEnv<'local>) -> jni::errors::Result<JThrowable<'local>> {
let throwable: JObject = match self {
ExampleError::Exception(exception) => {
// The error was caused by a Java exception.
// Here, `exception` is a `GlobalRef` pointing to a Java `Throwable`. It
// will be dropped at the end of this `match` arm. We'll use
// `new_local_ref` to create a local reference that will outlive the
// `GlobalRef`.
env.new_local_ref(&exception)?
}
ExampleError::Other(error) => {
// The error was caused by something that happened in Rust code. Create a
// new `java.lang.Error` to represent it.
let error_string = env.new_string(error.to_string())?;
env.new_object(
"java/lang/Error",
"(Ljava/lang/String;)V",
&[
(&error_string).into(),
],
)?
}
};
Ok(JThrowable::from(throwable))
}
}
Sourcepub fn auto_local<O>(&self, obj: O) -> AutoLocal<'local, O>
pub fn auto_local<O>(&self, obj: O) -> AutoLocal<'local, O>
Creates a new auto-deleted local reference.
See also with_local_frame
method that
can be more convenient when you create a bounded number of local references
but cannot rely on automatic de-allocation (e.g., in case of recursion, deep call stacks,
permanently-attached native threads, etc.).
Sourcepub fn delete_local_ref<'other_local, O>(&self, obj: O) -> Result<(), Error>
pub fn delete_local_ref<'other_local, O>(&self, obj: O) -> Result<(), Error>
Deletes the local reference.
Local references are valid for the duration of a native method call. They are freed automatically after the native method returns. Each local reference costs some amount of Java Virtual Machine resource. Programmers need to make sure that native methods do not excessively allocate local references. Although local references are automatically freed after the native method returns to Java, excessive allocation of local references may cause the VM to run out of memory during the execution of a native method.
In most cases it is better to use AutoLocal
(see auto_local
method)
or with_local_frame
instead of direct delete_local_ref
calls.
obj
can be a mutable borrow of a local reference (such as
&mut JObject
) instead of the local reference itself (such as
JObject
). In this case, the local reference will still exist after
this method returns, but it will be null.
Sourcepub fn push_local_frame(&self, capacity: i32) -> Result<(), Error>
pub fn push_local_frame(&self, capacity: i32) -> Result<(), Error>
Creates a new local reference frame, in which at least a given number of local references can be created.
Returns Err
on failure, with a pending OutOfMemoryError
.
Prefer to use
with_local_frame
instead of direct push_local_frame
/pop_local_frame
calls.
See also auto_local
method
and AutoLocal
type — that approach can be more convenient in loops.
Sourcepub unsafe fn pop_local_frame(
&self,
result: &JObject<'_>,
) -> Result<JObject<'local>, Error>
pub unsafe fn pop_local_frame( &self, result: &JObject<'_>, ) -> Result<JObject<'local>, Error>
Pops off the current local reference frame, frees all the local
references allocated on the current stack frame, except the result
,
which is returned from this function and remains valid.
The resulting JObject
will be NULL
iff result
is NULL
.
This method allows direct control of local frames, but it can cause
undefined behavior and is therefore unsafe. Prefer
JNIEnv::with_local_frame
instead.
§Safety
Any local references created after the most recent call to
JNIEnv::push_local_frame
(or the underlying JNI function) must not
be used after calling this method.
Sourcepub fn with_local_frame<F, T, E>(&mut self, capacity: i32, f: F) -> Result<T, E>
pub fn with_local_frame<F, T, E>(&mut self, capacity: i32, f: F) -> Result<T, E>
Executes the given function in a new local reference frame, in which at least a given number of references can be created. Once this method returns, all references allocated in the frame are freed.
If a frame can’t be allocated with the requested capacity for local
references, returns Err
with a pending OutOfMemoryError
.
Since local references created within this frame won’t be accessible to the calling
frame then if you need to pass an object back to the caller then you can do that via a
GlobalRef
/ [Self::make_global
].
Sourcepub fn with_local_frame_returning_local<F, E>(
&mut self,
capacity: i32,
f: F,
) -> Result<JObject<'local>, E>
pub fn with_local_frame_returning_local<F, E>( &mut self, capacity: i32, f: F, ) -> Result<JObject<'local>, E>
Executes the given function in a new local reference frame, in which at least a given number of references can be created. Once this method returns, all references allocated in the frame are freed, except the one that the function returns, which remains valid.
If a frame can’t be allocated with the requested capacity for local
references, returns Err
with a pending OutOfMemoryError
.
Since the low-level JNI interface has support for passing back a single local reference
from a local frame as special-case optimization, this alternative to with_local_frame
exposes that capability to return a local reference without needing to create a
temporary GlobalRef
.
Sourcepub fn alloc_object<'other_local, T>(
&mut self,
class: T,
) -> Result<JObject<'local>, Error>
pub fn alloc_object<'other_local, T>( &mut self, class: T, ) -> Result<JObject<'local>, Error>
Allocates a new object from a class descriptor without running a constructor.
Sourcepub fn get_method_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JMethodID, Error>
pub fn get_method_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JMethodID, Error>
Look up a method by class descriptor, name, and signature.
§Example
let method_id: JMethodID =
env.get_method_id("java/lang/String", "substring", "(II)Ljava/lang/String;")?;
Sourcepub fn get_static_method_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JStaticMethodID, Error>
pub fn get_static_method_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JStaticMethodID, Error>
Look up a static method by class descriptor, name, and signature.
§Example
let method_id: JStaticMethodID =
env.get_static_method_id("java/lang/String", "valueOf", "(I)Ljava/lang/String;")?;
Sourcepub fn get_field_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JFieldID, Error>
pub fn get_field_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JFieldID, Error>
Look up the field ID for a class/name/type combination.
§Example
let field_id: JFieldID = env.get_field_id("com/my/Class", "intField", "I")?;
Sourcepub fn get_static_field_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JStaticFieldID, Error>
pub fn get_static_field_id<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, ) -> Result<JStaticFieldID, Error>
Look up the static field ID for a class/name/type combination.
§Example
let field_id: JStaticFieldID = env.get_static_field_id("com/my/Class", "intField", "I")?;
Sourcepub fn get_object_class<'other_local, O>(
&self,
obj: O,
) -> Result<JClass<'local>, Error>
pub fn get_object_class<'other_local, O>( &self, obj: O, ) -> Result<JClass<'local>, Error>
Get the class for an object.
Sourcepub unsafe fn call_static_method_unchecked<'other_local, T, U>(
&mut self,
class: T,
method_id: U,
ret: ReturnType,
args: &[jvalue],
) -> Result<JValueGen<JObject<'local>>, Error>
pub unsafe fn call_static_method_unchecked<'other_local, T, U>( &mut self, class: T, method_id: U, ret: ReturnType, args: &[jvalue], ) -> Result<JValueGen<JObject<'local>>, Error>
Call a static method in an unsafe manner. This does nothing to check whether the method is valid to call on the class, whether the return type is correct, or whether the number of args is valid for the method.
Under the hood, this simply calls the CallStatic<Type>MethodA
method
with the provided arguments.
§Safety
The provided JMethodID must be valid, and match the types and number of arguments, and return type. If these are incorrect, the JVM may crash. The JMethodID must also match the passed type.
Sourcepub unsafe fn call_method_unchecked<'other_local, O, T>(
&mut self,
obj: O,
method_id: T,
ret: ReturnType,
args: &[jvalue],
) -> Result<JValueGen<JObject<'local>>, Error>
pub unsafe fn call_method_unchecked<'other_local, O, T>( &mut self, obj: O, method_id: T, ret: ReturnType, args: &[jvalue], ) -> Result<JValueGen<JObject<'local>>, Error>
Call an object method in an unsafe manner. This does nothing to check whether the method is valid to call on the object, whether the return type is correct, or whether the number of args is valid for the method.
Under the hood, this simply calls the Call<Type>MethodA
method with
the provided arguments.
§Safety
The provided JMethodID must be valid, and match the types and number of arguments, and return type. If these are incorrect, the JVM may crash. The JMethodID must also match the passed type.
Sourcepub fn call_method<'other_local, O, S, T>(
&mut self,
obj: O,
name: S,
sig: T,
args: &[JValueGen<&JObject<'_>>],
) -> Result<JValueGen<JObject<'local>>, Error>
pub fn call_method<'other_local, O, S, T>( &mut self, obj: O, name: S, sig: T, args: &[JValueGen<&JObject<'_>>], ) -> Result<JValueGen<JObject<'local>>, Error>
Calls an object method safely. This comes with a number of lookups/checks. It
- Parses the type signature to find the number of arguments and return type
- Looks up the JClass for the given object.
- Looks up the JMethodID for the class/name/signature combination
- Ensures that the number/types of args matches the signature
- Cannot check an object’s type - but primitive types are matched against each other (including Object)
- Calls
call_method_unchecked
with the verified safe arguments.
Note: this may cause a Java exception if the arguments are the wrong type, in addition to if the method itself throws.
Sourcepub fn call_static_method<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
args: &[JValueGen<&JObject<'_>>],
) -> Result<JValueGen<JObject<'local>>, Error>
pub fn call_static_method<'other_local, T, U, V>( &mut self, class: T, name: U, sig: V, args: &[JValueGen<&JObject<'_>>], ) -> Result<JValueGen<JObject<'local>>, Error>
Calls a static method safely. This comes with a number of lookups/checks. It
- Parses the type signature to find the number of arguments and return type
- Looks up the JMethodID for the class/name/signature combination
- Ensures that the number/types of args matches the signature
- Cannot check an object’s type - but primitive types are matched against each other (including Object)
- Calls
call_method_unchecked
with the verified safe arguments.
Note: this may cause a Java exception if the arguments are the wrong type, in addition to if the method itself throws.
Sourcepub fn new_object<'other_local, T, U>(
&mut self,
class: T,
ctor_sig: U,
ctor_args: &[JValueGen<&JObject<'_>>],
) -> Result<JObject<'local>, Error>
pub fn new_object<'other_local, T, U>( &mut self, class: T, ctor_sig: U, ctor_args: &[JValueGen<&JObject<'_>>], ) -> Result<JObject<'local>, Error>
Create a new object using a constructor. This is done safely using
checks similar to those in call_static_method
.
Sourcepub unsafe fn new_object_unchecked<'other_local, T>(
&mut self,
class: T,
ctor_id: JMethodID,
ctor_args: &[jvalue],
) -> Result<JObject<'local>, Error>
pub unsafe fn new_object_unchecked<'other_local, T>( &mut self, class: T, ctor_id: JMethodID, ctor_args: &[jvalue], ) -> Result<JObject<'local>, Error>
Create a new object using a constructor. Arguments aren’t checked
because of the JMethodID
usage.
§Safety
The provided JMethodID must be valid, and match the types and number of arguments, as well as return type (always an Object for a constructor). If these are incorrect, the JVM may crash. The JMethodID must also match the passed type.
Sourcepub fn get_list<'other_local_1, 'obj_ref>(
&mut self,
obj: &'obj_ref JObject<'other_local_1>,
) -> Result<JList<'local, 'other_local_1, 'obj_ref>, Error>where
'other_local_1: 'obj_ref,
pub fn get_list<'other_local_1, 'obj_ref>(
&mut self,
obj: &'obj_ref JObject<'other_local_1>,
) -> Result<JList<'local, 'other_local_1, 'obj_ref>, Error>where
'other_local_1: 'obj_ref,
Cast a JObject to a JList
. This won’t throw exceptions or return errors
in the event that the object isn’t actually a list, but the methods on
the resulting map object will.
Sourcepub fn get_map<'other_local_1, 'obj_ref>(
&mut self,
obj: &'obj_ref JObject<'other_local_1>,
) -> Result<JMap<'local, 'other_local_1, 'obj_ref>, Error>where
'other_local_1: 'obj_ref,
pub fn get_map<'other_local_1, 'obj_ref>(
&mut self,
obj: &'obj_ref JObject<'other_local_1>,
) -> Result<JMap<'local, 'other_local_1, 'obj_ref>, Error>where
'other_local_1: 'obj_ref,
Cast a JObject to a JMap. This won’t throw exceptions or return errors in the event that the object isn’t actually a map, but the methods on the resulting map object will.
Sourcepub unsafe fn get_string_unchecked<'other_local, 'obj_ref>(
&self,
obj: &'obj_ref JString<'other_local>,
) -> Result<JavaStr<'local, 'other_local, 'obj_ref>, Error>where
'other_local: 'obj_ref,
pub unsafe fn get_string_unchecked<'other_local, 'obj_ref>(
&self,
obj: &'obj_ref JString<'other_local>,
) -> Result<JavaStr<'local, 'other_local, 'obj_ref>, Error>where
'other_local: 'obj_ref,
Get a JavaStr
from a JString
. This allows conversions from java string
objects to rust strings.
This only entails calling GetStringUTFChars
, which will return a JavaStr
in Java’s
Modified UTF-8
format.
This doesn’t automatically decode Java’s modified UTF-8 format but you
can use .into()
to convert the returned JavaStr
into a Rust String
.
§Safety
The caller must guarantee that the Object passed in is an instance of java.lang.String
,
passing in anything else will lead to undefined behaviour (The JNI implementation
is likely to crash or abort the process).
§Errors
Returns an error if obj
is null
Sourcepub fn get_string<'other_local, 'obj_ref>(
&mut self,
obj: &'obj_ref JString<'other_local>,
) -> Result<JavaStr<'local, 'other_local, 'obj_ref>, Error>where
'other_local: 'obj_ref,
pub fn get_string<'other_local, 'obj_ref>(
&mut self,
obj: &'obj_ref JString<'other_local>,
) -> Result<JavaStr<'local, 'other_local, 'obj_ref>, Error>where
'other_local: 'obj_ref,
Get a JavaStr
from a JString
. This allows conversions from java string
objects to rust strings.
This entails checking that the given object is a java.lang.String
and
calling GetStringUTFChars
, which will return a JavaStr
in Java’s
Modified UTF-8
format.
This doesn’t automatically decode Java’s modified UTF-8 format but you
can use .into()
to convert the returned JavaStr
into a Rust String
.
§Performance
This function has a large relative performance impact compared to
Self::get_string_unchecked. For example it may be about five times
slower than get_string_unchecked
for very short string. This
performance penalty comes from the extra validation performed by this
function. If and only if you can guarantee that your obj
is of
java.lang.String
, use Self::get_string_unchecked.
§Errors
Returns an error if obj
is null
or is not an instance of java.lang.String
Sourcepub fn new_string<S>(&self, from: S) -> Result<JString<'local>, Error>
pub fn new_string<S>(&self, from: S) -> Result<JString<'local>, Error>
Create a new java string object from a rust string. This requires a re-encoding of rusts real UTF-8 strings to java’s modified UTF-8 format.
Sourcepub fn get_array_length<'other_local, 'array>(
&self,
array: &'array impl AsJArrayRaw<'other_local>,
) -> Result<i32, Error>
pub fn get_array_length<'other_local, 'array>( &self, array: &'array impl AsJArrayRaw<'other_local>, ) -> Result<i32, Error>
Get the length of a JPrimitiveArray
or JObjectArray
.
Sourcepub fn new_object_array<'other_local_1, 'other_local_2, T, U>(
&mut self,
length: i32,
element_class: T,
initial_element: U,
) -> Result<JObjectArray<'local>, Error>
pub fn new_object_array<'other_local_1, 'other_local_2, T, U>( &mut self, length: i32, element_class: T, initial_element: U, ) -> Result<JObjectArray<'local>, Error>
Construct a new array holding objects in class element_class
.
All elements are initially set to initial_element
.
This function returns a local reference, that must not be allocated excessively. See Java documentation for details.
Sourcepub fn get_object_array_element<'other_local>(
&mut self,
array: impl AsRef<JObjectArray<'other_local>>,
index: i32,
) -> Result<JObject<'local>, Error>
pub fn get_object_array_element<'other_local>( &mut self, array: impl AsRef<JObjectArray<'other_local>>, index: i32, ) -> Result<JObject<'local>, Error>
Returns a local reference to an element of the JObjectArray
array
.
Sourcepub fn set_object_array_element<'other_local_1, 'other_local_2>(
&self,
array: impl AsRef<JObjectArray<'other_local_1>>,
index: i32,
value: impl AsRef<JObject<'other_local_2>>,
) -> Result<(), Error>
pub fn set_object_array_element<'other_local_1, 'other_local_2>( &self, array: impl AsRef<JObjectArray<'other_local_1>>, index: i32, value: impl AsRef<JObject<'other_local_2>>, ) -> Result<(), Error>
Sets an element of the JObjectArray
array
.
Sourcepub fn byte_array_from_slice(
&self,
buf: &[u8],
) -> Result<JPrimitiveArray<'local, i8>, Error>
pub fn byte_array_from_slice( &self, buf: &[u8], ) -> Result<JPrimitiveArray<'local, i8>, Error>
Create a new java byte array from a rust byte slice.
Sourcepub fn convert_byte_array<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i8>>,
) -> Result<Vec<u8>, Error>
pub fn convert_byte_array<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i8>>, ) -> Result<Vec<u8>, Error>
Converts a java byte array to a rust vector of bytes.
Sourcepub fn new_boolean_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, u8>, Error>
pub fn new_boolean_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, u8>, Error>
Create a new java boolean array of supplied length.
Sourcepub fn new_byte_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, i8>, Error>
pub fn new_byte_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, i8>, Error>
Create a new java byte array of supplied length.
Sourcepub fn new_char_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, u16>, Error>
pub fn new_char_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, u16>, Error>
Create a new java char array of supplied length.
Sourcepub fn new_short_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, i16>, Error>
pub fn new_short_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, i16>, Error>
Create a new java short array of supplied length.
Sourcepub fn new_int_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, i32>, Error>
pub fn new_int_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, i32>, Error>
Create a new java int array of supplied length.
Sourcepub fn new_long_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, i64>, Error>
pub fn new_long_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, i64>, Error>
Create a new java long array of supplied length.
Sourcepub fn new_float_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, f32>, Error>
pub fn new_float_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, f32>, Error>
Create a new java float array of supplied length.
Sourcepub fn new_double_array(
&self,
length: i32,
) -> Result<JPrimitiveArray<'local, f64>, Error>
pub fn new_double_array( &self, length: i32, ) -> Result<JPrimitiveArray<'local, f64>, Error>
Create a new java double array of supplied length.
Sourcepub fn get_boolean_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, u8>>,
start: i32,
buf: &mut [u8],
) -> Result<(), Error>
pub fn get_boolean_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, u8>>, start: i32, buf: &mut [u8], ) -> Result<(), Error>
Copy elements of the java boolean array from the start
index to the
buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn get_byte_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i8>>,
start: i32,
buf: &mut [i8],
) -> Result<(), Error>
pub fn get_byte_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i8>>, start: i32, buf: &mut [i8], ) -> Result<(), Error>
Copy elements of the java byte array from the start
index to the buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn get_char_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, u16>>,
start: i32,
buf: &mut [u16],
) -> Result<(), Error>
pub fn get_char_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, u16>>, start: i32, buf: &mut [u16], ) -> Result<(), Error>
Copy elements of the java char array from the start
index to the
buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn get_short_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i16>>,
start: i32,
buf: &mut [i16],
) -> Result<(), Error>
pub fn get_short_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i16>>, start: i32, buf: &mut [i16], ) -> Result<(), Error>
Copy elements of the java short array from the start
index to the
buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn get_int_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i32>>,
start: i32,
buf: &mut [i32],
) -> Result<(), Error>
pub fn get_int_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i32>>, start: i32, buf: &mut [i32], ) -> Result<(), Error>
Copy elements of the java int array from the start
index to the
buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn get_long_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i64>>,
start: i32,
buf: &mut [i64],
) -> Result<(), Error>
pub fn get_long_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i64>>, start: i32, buf: &mut [i64], ) -> Result<(), Error>
Copy elements of the java long array from the start
index to the
buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn get_float_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, f32>>,
start: i32,
buf: &mut [f32],
) -> Result<(), Error>
pub fn get_float_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, f32>>, start: i32, buf: &mut [f32], ) -> Result<(), Error>
Copy elements of the java float array from the start
index to the
buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn get_double_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, f64>>,
start: i32,
buf: &mut [f64],
) -> Result<(), Error>
pub fn get_double_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, f64>>, start: i32, buf: &mut [f64], ) -> Result<(), Error>
Copy elements of the java double array from the start
index to the
buf
slice. The number of copied elements is equal to the buf
length.
§Errors
If start
is negative or start + buf.len()
is greater than array.length
then no elements are copied, an ArrayIndexOutOfBoundsException
is thrown,
and Err
is returned.
Sourcepub fn set_boolean_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, u8>>,
start: i32,
buf: &[u8],
) -> Result<(), Error>
pub fn set_boolean_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, u8>>, start: i32, buf: &[u8], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java boolean array at the
start
index.
Sourcepub fn set_byte_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i8>>,
start: i32,
buf: &[i8],
) -> Result<(), Error>
pub fn set_byte_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i8>>, start: i32, buf: &[i8], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java byte array at the
start
index.
Sourcepub fn set_char_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, u16>>,
start: i32,
buf: &[u16],
) -> Result<(), Error>
pub fn set_char_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, u16>>, start: i32, buf: &[u16], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java char array at the
start
index.
Sourcepub fn set_short_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i16>>,
start: i32,
buf: &[i16],
) -> Result<(), Error>
pub fn set_short_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i16>>, start: i32, buf: &[i16], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java short array at the
start
index.
Sourcepub fn set_int_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i32>>,
start: i32,
buf: &[i32],
) -> Result<(), Error>
pub fn set_int_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i32>>, start: i32, buf: &[i32], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java int array at the
start
index.
Sourcepub fn set_long_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, i64>>,
start: i32,
buf: &[i64],
) -> Result<(), Error>
pub fn set_long_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, i64>>, start: i32, buf: &[i64], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java long array at the
start
index.
Sourcepub fn set_float_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, f32>>,
start: i32,
buf: &[f32],
) -> Result<(), Error>
pub fn set_float_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, f32>>, start: i32, buf: &[f32], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java float array at the
start
index.
Sourcepub fn set_double_array_region<'other_local>(
&self,
array: impl AsRef<JPrimitiveArray<'other_local, f64>>,
start: i32,
buf: &[f64],
) -> Result<(), Error>
pub fn set_double_array_region<'other_local>( &self, array: impl AsRef<JPrimitiveArray<'other_local, f64>>, start: i32, buf: &[f64], ) -> Result<(), Error>
Copy the contents of the buf
slice to the java double array at the
start
index.
Sourcepub fn get_field_unchecked<'other_local, O, T>(
&mut self,
obj: O,
field: T,
ty: ReturnType,
) -> Result<JValueGen<JObject<'local>>, Error>
pub fn get_field_unchecked<'other_local, O, T>( &mut self, obj: O, field: T, ty: ReturnType, ) -> Result<JValueGen<JObject<'local>>, Error>
Get a field without checking the provided type against the actual field.
Sourcepub fn set_field_unchecked<'other_local, O, T>(
&mut self,
obj: O,
field: T,
val: JValueGen<&JObject<'_>>,
) -> Result<(), Error>
pub fn set_field_unchecked<'other_local, O, T>( &mut self, obj: O, field: T, val: JValueGen<&JObject<'_>>, ) -> Result<(), Error>
Set a field without any type checking.
Sourcepub fn get_field<'other_local, O, S, T>(
&mut self,
obj: O,
name: S,
ty: T,
) -> Result<JValueGen<JObject<'local>>, Error>
pub fn get_field<'other_local, O, S, T>( &mut self, obj: O, name: S, ty: T, ) -> Result<JValueGen<JObject<'local>>, Error>
Get a field. Requires an object class lookup and a field id lookup internally.
Sourcepub fn set_field<'other_local, O, S, T>(
&mut self,
obj: O,
name: S,
ty: T,
val: JValueGen<&JObject<'_>>,
) -> Result<(), Error>
pub fn set_field<'other_local, O, S, T>( &mut self, obj: O, name: S, ty: T, val: JValueGen<&JObject<'_>>, ) -> Result<(), Error>
Set a field. Does the same lookups as get_field
and ensures that the
type matches the given value.
Sourcepub fn get_static_field_unchecked<'other_local, T, U>(
&mut self,
class: T,
field: U,
ty: JavaType,
) -> Result<JValueGen<JObject<'local>>, Error>
pub fn get_static_field_unchecked<'other_local, T, U>( &mut self, class: T, field: U, ty: JavaType, ) -> Result<JValueGen<JObject<'local>>, Error>
Get a static field without checking the provided type against the actual field.
Sourcepub fn get_static_field<'other_local, T, U, V>(
&mut self,
class: T,
field: U,
sig: V,
) -> Result<JValueGen<JObject<'local>>, Error>
pub fn get_static_field<'other_local, T, U, V>( &mut self, class: T, field: U, sig: V, ) -> Result<JValueGen<JObject<'local>>, Error>
Get a static field. Requires a class lookup and a field id lookup internally.
Sourcepub fn set_static_field<'other_local, T, U>(
&mut self,
class: T,
field: U,
value: JValueGen<&JObject<'_>>,
) -> Result<(), Error>
pub fn set_static_field<'other_local, T, U>( &mut self, class: T, field: U, value: JValueGen<&JObject<'_>>, ) -> Result<(), Error>
Set a static field. Requires a class lookup and a field id lookup internally.
Sourcepub unsafe fn set_rust_field<'other_local, O, S, T>(
&mut self,
obj: O,
field: S,
rust_object: T,
) -> Result<(), Error>
pub unsafe fn set_rust_field<'other_local, O, S, T>( &mut self, obj: O, field: S, rust_object: T, ) -> Result<(), Error>
Surrenders ownership of a Rust value to Java.
This requires an object with a long
field to store the pointer.
In Java the property may look like:
private long myRustValueHandle = 0;
Or, in Kotlin the property may look like:
private var myRustValueHandle: Long = 0
Note that private
properties are accessible to JNI which may be
preferable to avoid exposing the handles to more code than necessary
(since the handles are usually only meaningful to Rust code).
The Rust value will be implicitly wrapped in a Box<Mutex<T>>
.
The Java object will be locked while changing the field value.
§Safety
It’s important to note that using this API will leak memory if
Self::take_rust_field
is never called so that the Rust type may be
dropped.
One suggestion that may help ensure that a set Rust field will be
cleaned up later is for the Java object to implement Closeable
and let
people use a use
block (Kotlin) or try-with-resources
(Java).
DO NOT make a copy of the handle stored in one of these fields since that could lead to a use-after-free error if the Rust type is taken and dropped multiple times from Rust. If you need to copy an object with one of these fields then the field should be zero initialized in the copy.
Sourcepub unsafe fn get_rust_field<'other_local, O, S, T>(
&mut self,
obj: O,
field: S,
) -> Result<MutexGuard<'_, T>, Error>
pub unsafe fn get_rust_field<'other_local, O, S, T>( &mut self, obj: O, field: S, ) -> Result<MutexGuard<'_, T>, Error>
Gets a lock on a Rust value that’s been given to a Java object.
Java still retains ownership and Self::take_rust_field
will still
need to be called at some point.
The Java object will be locked before reading the field value but the
Java object lock will be released after the Rust Mutex
lock for the
field value has been taken (i.e the Java object won’t be locked once
this function returns).
§Safety
Checks for a null pointer, but assumes that the data it points to is valid for T.
Sourcepub unsafe fn take_rust_field<'other_local, O, S, T>(
&mut self,
obj: O,
field: S,
) -> Result<T, Error>
pub unsafe fn take_rust_field<'other_local, O, S, T>( &mut self, obj: O, field: S, ) -> Result<T, Error>
Take a Rust field back from Java.
It sets the field to a null pointer to signal that it’s empty.
The Java object will be locked before taking the field value.
§Safety
This will make sure that the pointer is non-null, but still assumes that the data it points to is valid for T.
Sourcepub fn lock_obj<'other_local, O>(
&self,
obj: O,
) -> Result<MonitorGuard<'local>, Error>
pub fn lock_obj<'other_local, O>( &self, obj: O, ) -> Result<MonitorGuard<'local>, Error>
Lock a Java object. The MonitorGuard that this returns is responsible for ensuring that it gets unlocked.
Sourcepub fn get_native_interface(&self) -> *mut *const JNINativeInterface_
pub fn get_native_interface(&self) -> *mut *const JNINativeInterface_
Returns underlying sys::JNIEnv
interface.
Sourcepub fn get_java_vm(&self) -> Result<JavaVM, Error>
pub fn get_java_vm(&self) -> Result<JavaVM, Error>
Returns the Java VM interface.
Sourcepub fn ensure_local_capacity(&self, capacity: i32) -> Result<(), Error>
pub fn ensure_local_capacity(&self, capacity: i32) -> Result<(), Error>
Ensures that at least a given number of local references can be created in the current thread.
Sourcepub fn register_native_methods<'other_local, T>(
&mut self,
class: T,
methods: &[NativeMethod],
) -> Result<(), Error>
pub fn register_native_methods<'other_local, T>( &mut self, class: T, methods: &[NativeMethod], ) -> Result<(), Error>
Bind function pointers to native methods of class according to method name and signature. For details see documentation.
Sourcepub fn unregister_native_methods<'other_local, T>(
&mut self,
class: T,
) -> Result<(), Error>
pub fn unregister_native_methods<'other_local, T>( &mut self, class: T, ) -> Result<(), Error>
Unbind all native methods of class.
Sourcepub unsafe fn get_array_elements<'other_local, 'array, T>(
&mut self,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<AutoElements<'local, 'other_local, 'array, T>, Error>where
T: TypeArray,
pub unsafe fn get_array_elements<'other_local, 'array, T>(
&mut self,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<AutoElements<'local, 'other_local, 'array, T>, Error>where
T: TypeArray,
Returns an AutoElements
to access the elements of the given Java array
.
The elements are accessible until the returned auto-release guard is dropped.
The returned array may be a copy of the Java array and changes made to
the returned array will not necessarily be reflected in the original
array until the AutoElements
guard is dropped.
If you know in advance that you will only be reading from the array then
pass ReleaseMode::NoCopyBack
so that the JNI implementation knows
that it’s not necessary to copy any data back to the original Java array
when the AutoElements
guard is dropped.
Since the returned array may be a copy of the Java array, changes made to the
returned array will not necessarily be reflected in the original array until
the corresponding Release*ArrayElements
JNI method is called.
AutoElements
has a commit() method, to force a copy back of pending
array changes if needed (and without releasing it).
§Safety
§No data races
This API has no built-in synchronization that ensures there won’t be any data races while accessing the array elements.
To avoid undefined behaviour it is the caller’s responsibility to ensure there will be no data races between other Rust or Java threads trying to access the same array.
Acquiring a MonitorGuard
lock for the array
could be one way of ensuring
mutual exclusion between Rust and Java threads, so long as the Java threads
also acquire the same lock via synchronized(array) {}
.
§No aliasing
Callers must not create more than one AutoElements
or
AutoElementsCritical
per Java array at the same time - even if
there is no risk of a data race.
The reason for this restriction is that AutoElements
and
AutoElementsCritical
implement DerefMut
which can provide a
mutable &mut [T]
slice reference for the elements and it would
constitute undefined behaviour to allow there to be more than one
mutable reference that points to the same memory.
§jboolean elements
Keep in mind that arrays of jboolean
values should only ever hold
values of 0
or 1
because any other value could lead to undefined
behaviour within the JVM.
Also see
get_array_elements_critical
which
imposes additional restrictions that make it less likely to incur the
cost of copying the array elements.
Sourcepub unsafe fn get_array_elements_critical<'other_local, 'array, 'env, T>(
&'env mut self,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<AutoElementsCritical<'local, 'other_local, 'array, 'env, T>, Error>where
T: TypeArray,
pub unsafe fn get_array_elements_critical<'other_local, 'array, 'env, T>(
&'env mut self,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<AutoElementsCritical<'local, 'other_local, 'array, 'env, T>, Error>where
T: TypeArray,
Returns an AutoElementsCritical
to access the elements of the given Java array
.
The elements are accessible during the critical section that exists until the returned auto-release guard is dropped.
This API imposes some strict restrictions that help the JNI implementation avoid any need to copy the underlying array elements before making them accessible to native code:
- No other use of JNI calls are allowed (on the same thread) within the critical
section that exists while holding the
AutoElementsCritical
guard. - No system calls can be made (Such as
read
) that may depend on a result from another Java thread.
The JNI spec does not specify what will happen if these rules aren’t adhered to but it should be assumed it will lead to undefined behaviour, likely deadlock and possible program termination.
Even with these restrictions the returned array may still be a copy of
the Java array and changes made to the returned array will not
necessarily be reflected in the original array until the AutoElementsCritical
guard is dropped.
If you know in advance that you will only be reading from the array then
pass ReleaseMode::NoCopyBack
so that the JNI implementation knows
that it’s not necessary to copy any data back to the original Java array
when the AutoElementsCritical
guard is dropped.
A nested scope or explicit use of std::mem::drop
can be used to
control when the returned AutoElementsCritical
is dropped to
minimize the length of the critical section.
If the given array is null
, an Error::NullPtr
is returned.
§Safety
§Critical Section Restrictions
Although this API takes a mutable reference to a JNIEnv
which should
ensure that it’s not possible to call JNI, this API is still marked as
unsafe
due to the complex, far-reaching nature of the critical-section
restrictions imposed here that can’t be guaranteed simply through Rust’s
borrow checker rules.
The rules above about JNI usage and system calls must be adhered to.
Using this API implies:
- All garbage collection will likely be paused during the critical section
- Any use of JNI in other threads may block if they need to allocate memory (due to the garbage collector being paused)
- Any use of system calls that will wait for a result from another Java thread could deadlock if that other thread is blocked by a paused garbage collector.
A failure to adhere to the critical section rules could lead to any undefined behaviour, including aborting the program.
§No data races
This API has no built-in synchronization that ensures there won’t be any data races while accessing the array elements.
To avoid undefined behaviour it is the caller’s responsibility to ensure there will be no data races between other Rust or Java threads trying to access the same array.
Acquiring a MonitorGuard
lock for the array
could be one way of ensuring
mutual exclusion between Rust and Java threads, so long as the Java threads
also acquire the same lock via synchronized(array) {}
.
§No aliasing
Callers must not create more than one AutoElements
or
AutoElementsCritical
per Java array at the same time - even if
there is no risk of a data race.
The reason for this restriction is that AutoElements
and
AutoElementsCritical
implement DerefMut
which can provide a
mutable &mut [T]
slice reference for the elements and it would
constitute undefined behaviour to allow there to be more than one
mutable reference that points to the same memory.
§jboolean elements
Keep in mind that arrays of jboolean
values should only ever hold
values of 0
or 1
because any other value could lead to undefined
behaviour within the JVM.
Also see get_array_elements
which has fewer
restrictions, but is is more likely to incur a cost from copying the
array elements.