use std::{
marker::PhantomData,
os::raw::{c_char, c_void},
ptr, str,
str::FromStr,
sync::{Mutex, MutexGuard},
};
use log::warn;
use crate::{
descriptors::Desc,
errors::*,
objects::{
AutoElements, AutoElementsCritical, AutoLocal, GlobalRef, JByteBuffer, JClass, JFieldID,
JList, JMap, JMethodID, JObject, JStaticFieldID, JStaticMethodID, JString, JThrowable,
JValue, JValueOwned, ReleaseMode, TypeArray, WeakRef,
},
signature::{JavaType, Primitive, TypeSignature},
strings::{JNIString, JavaStr},
sys::{
self, jarray, jboolean, jbyte, jchar, jdouble, jfloat, jint, jlong, jshort, jsize, jvalue,
JNINativeMethod,
},
JNIVersion, JavaVM,
};
use crate::{
errors::Error::JniCall,
objects::{
JBooleanArray, JByteArray, JCharArray, JDoubleArray, JFloatArray, JIntArray, JLongArray,
JObjectArray, JPrimitiveArray, JShortArray,
},
};
use crate::{objects::AsJArrayRaw, signature::ReturnType};
#[repr(transparent)]
#[derive(Debug)]
pub struct JNIEnv<'local> {
internal: *mut sys::JNIEnv,
lifetime: PhantomData<&'local ()>,
}
impl<'local> JNIEnv<'local> {
pub unsafe fn from_raw(ptr: *mut sys::JNIEnv) -> Result<Self> {
non_null!(ptr, "from_raw ptr argument");
Ok(JNIEnv {
internal: ptr,
lifetime: PhantomData,
})
}
pub fn get_raw(&self) -> *mut sys::JNIEnv {
self.internal
}
pub unsafe fn unsafe_clone(&self) -> Self {
Self {
internal: self.internal,
lifetime: self.lifetime,
}
}
pub fn get_version(&self) -> Result<JNIVersion> {
Ok(jni_unchecked!(self.internal, GetVersion).into())
}
pub fn define_class<S>(
&mut self,
name: S,
loader: &JObject,
buf: &[u8],
) -> Result<JClass<'local>>
where
S: Into<JNIString>,
{
let name = name.into();
self.define_class_impl(name.as_ptr(), loader, buf)
}
pub fn define_unnamed_class(&mut self, loader: &JObject, buf: &[u8]) -> Result<JClass<'local>> {
self.define_class_impl(ptr::null(), loader, buf)
}
fn define_class_impl(
&mut self,
name: *const c_char,
loader: &JObject,
buf: &[u8],
) -> Result<JClass<'local>> {
let class = jni_non_null_call!(
self.internal,
DefineClass,
name,
loader.as_raw(),
buf.as_ptr() as *const jbyte,
buf.len() as jsize
);
Ok(unsafe { JClass::from_raw(class) })
}
pub fn define_class_bytearray<S>(
&mut self,
name: S,
loader: &JObject,
buf: &AutoElements<'_, '_, '_, jbyte>,
) -> Result<JClass<'local>>
where
S: Into<JNIString>,
{
let name = name.into();
let class = jni_non_null_call!(
self.internal,
DefineClass,
name.as_ptr(),
loader.as_raw(),
buf.as_ptr(),
buf.len() as _
);
Ok(unsafe { JClass::from_raw(class) })
}
pub fn find_class<S>(&mut self, name: S) -> Result<JClass<'local>>
where
S: Into<JNIString>,
{
let name = name.into();
let class = jni_non_null_call!(self.internal, FindClass, name.as_ptr());
Ok(unsafe { JClass::from_raw(class) })
}
pub fn get_superclass<'other_local, T>(&mut self, class: T) -> Result<Option<JClass<'local>>>
where
T: Desc<'local, JClass<'other_local>>,
{
let class = class.lookup(self)?;
let superclass = unsafe {
JClass::from_raw(jni_unchecked!(
self.internal,
GetSuperclass,
class.as_ref().as_raw()
))
};
Ok((!superclass.is_null()).then_some(superclass))
}
pub fn is_assignable_from<'other_local_1, 'other_local_2, T, U>(
&mut self,
class1: T,
class2: U,
) -> Result<bool>
where
T: Desc<'local, JClass<'other_local_1>>,
U: Desc<'local, JClass<'other_local_2>>,
{
let class1 = class1.lookup(self)?;
let class2 = class2.lookup(self)?;
Ok(jni_unchecked!(
self.internal,
IsAssignableFrom,
class1.as_ref().as_raw(),
class2.as_ref().as_raw()
) == sys::JNI_TRUE)
}
pub fn is_instance_of<'other_local_1, 'other_local_2, O, T>(
&mut self,
object: O,
class: T,
) -> Result<bool>
where
O: AsRef<JObject<'other_local_1>>,
T: Desc<'local, JClass<'other_local_2>>,
{
let class = class.lookup(self)?;
Ok(jni_unchecked!(
self.internal,
IsInstanceOf,
object.as_ref().as_raw(),
class.as_ref().as_raw()
) == sys::JNI_TRUE)
}
pub fn is_same_object<'other_local_1, 'other_local_2, O, T>(
&self,
ref1: O,
ref2: T,
) -> Result<bool>
where
O: AsRef<JObject<'other_local_1>>,
T: AsRef<JObject<'other_local_2>>,
{
Ok(jni_unchecked!(
self.internal,
IsSameObject,
ref1.as_ref().as_raw(),
ref2.as_ref().as_raw()
) == sys::JNI_TRUE)
}
pub fn throw<'other_local, E>(&mut self, obj: E) -> Result<()>
where
E: Desc<'local, JThrowable<'other_local>>,
{
let throwable = obj.lookup(self)?;
let res: i32 = jni_unchecked!(self.internal, Throw, throwable.as_ref().as_raw());
drop(throwable);
if res == 0 {
Ok(())
} else {
Err(Error::ThrowFailed(res))
}
}
pub fn throw_new<'other_local, S, T>(&mut self, class: T, msg: S) -> Result<()>
where
S: Into<JNIString>,
T: Desc<'local, JClass<'other_local>>,
{
let class = class.lookup(self)?;
let msg = msg.into();
let res: i32 = jni_unchecked!(
self.internal,
ThrowNew,
class.as_ref().as_raw(),
msg.as_ptr()
);
drop(class);
if res == 0 {
Ok(())
} else {
Err(Error::ThrowFailed(res))
}
}
pub fn exception_occurred(&mut self) -> Result<JThrowable<'local>> {
let throwable = jni_unchecked!(self.internal, ExceptionOccurred);
Ok(unsafe { JThrowable::from_raw(throwable) })
}
pub fn exception_describe(&self) -> Result<()> {
jni_unchecked!(self.internal, ExceptionDescribe);
Ok(())
}
pub fn exception_clear(&self) -> Result<()> {
jni_unchecked!(self.internal, ExceptionClear);
Ok(())
}
#[allow(unused_variables, unreachable_code)]
pub fn fatal_error<S: Into<JNIString>>(&self, msg: S) -> ! {
let msg = msg.into();
let res: Result<()> = catch!({
jni_unchecked!(self.internal, FatalError, msg.as_ptr());
unreachable!()
});
panic!("{:?}", res.unwrap_err());
}
pub fn exception_check(&self) -> Result<bool> {
let check = jni_unchecked!(self.internal, ExceptionCheck) == sys::JNI_TRUE;
Ok(check)
}
pub unsafe fn new_direct_byte_buffer(
&mut self,
data: *mut u8,
len: usize,
) -> Result<JByteBuffer<'local>> {
non_null!(data, "new_direct_byte_buffer data argument");
let obj = jni_non_null_call!(
self.internal,
NewDirectByteBuffer,
data as *mut c_void,
len as jlong
);
Ok(JByteBuffer::from_raw(obj))
}
pub fn get_direct_buffer_address(&self, buf: &JByteBuffer) -> Result<*mut u8> {
non_null!(buf, "get_direct_buffer_address argument");
let ptr = jni_unchecked!(self.internal, GetDirectBufferAddress, buf.as_raw());
non_null!(ptr, "get_direct_buffer_address return value");
Ok(ptr as _)
}
pub fn get_direct_buffer_capacity(&self, buf: &JByteBuffer) -> Result<usize> {
non_null!(buf, "get_direct_buffer_capacity argument");
let capacity = jni_unchecked!(self.internal, GetDirectBufferCapacity, buf.as_raw());
match capacity {
-1 => Err(Error::JniCall(JniError::Unknown)),
_ => Ok(capacity as usize),
}
}
pub fn new_global_ref<'other_local, O>(&self, obj: O) -> Result<GlobalRef>
where
O: AsRef<JObject<'other_local>>,
{
let jvm = self.get_java_vm()?;
let new_ref = jni_unchecked!(self.internal, NewGlobalRef, obj.as_ref().as_raw());
let global = unsafe { GlobalRef::from_raw(jvm, new_ref) };
Ok(global)
}
pub fn new_weak_ref<'other_local, O>(&self, obj: O) -> Result<Option<WeakRef>>
where
O: AsRef<JObject<'other_local>>,
{
let vm = self.get_java_vm()?;
let obj = obj.as_ref().as_raw();
if obj.is_null() {
return Ok(None);
}
let weak: sys::jweak = jni_non_void_call!(self.internal, NewWeakGlobalRef, obj);
if weak.is_null() {
return Ok(None);
}
let weak = unsafe { WeakRef::from_raw(vm, weak) };
Ok(Some(weak))
}
pub fn new_local_ref<'other_local, O>(&self, obj: O) -> Result<JObject<'local>>
where
O: AsRef<JObject<'other_local>>,
{
let local = jni_unchecked!(self.internal, NewLocalRef, obj.as_ref().as_raw());
Ok(unsafe { JObject::from_raw(local) })
}
pub fn auto_local<O>(&self, obj: O) -> AutoLocal<'local, O>
where
O: Into<JObject<'local>>,
{
AutoLocal::new(obj, self)
}
pub fn delete_local_ref<'other_local, O>(&self, obj: O) -> Result<()>
where
O: Into<JObject<'other_local>>,
{
let raw = obj.into().into_raw();
jni_unchecked!(self.internal, DeleteLocalRef, raw);
Ok(())
}
pub fn push_local_frame(&self, capacity: i32) -> Result<()> {
let res = jni_unchecked!(self.internal, PushLocalFrame, capacity);
jni_error_code_to_result(res)
}
pub unsafe fn pop_local_frame(&self, result: &JObject) -> Result<JObject<'local>> {
Ok(JObject::from_raw(jni_unchecked!(
self.internal,
PopLocalFrame,
result.as_raw()
)))
}
pub fn with_local_frame<F, T, E>(&mut self, capacity: i32, f: F) -> std::result::Result<T, E>
where
F: FnOnce(&mut JNIEnv) -> std::result::Result<T, E>,
E: From<Error>,
{
unsafe {
self.push_local_frame(capacity)?;
let ret = f(self);
self.pop_local_frame(&JObject::null())?;
ret
}
}
pub fn with_local_frame_returning_local<F, E>(
&mut self,
capacity: i32,
f: F,
) -> std::result::Result<JObject<'local>, E>
where
F: for<'new_local> FnOnce(
&mut JNIEnv<'new_local>,
) -> std::result::Result<JObject<'new_local>, E>,
E: From<Error>,
{
unsafe {
self.push_local_frame(capacity)?;
match f(self) {
Ok(obj) => {
let obj = self.pop_local_frame(&obj)?;
Ok(obj)
}
Err(err) => {
self.pop_local_frame(&JObject::null())?;
Err(err)
}
}
}
}
pub fn alloc_object<'other_local, T>(&mut self, class: T) -> Result<JObject<'local>>
where
T: Desc<'local, JClass<'other_local>>,
{
let class = class.lookup(self)?;
let obj = jni_non_null_call!(self.internal, AllocObject, class.as_ref().as_raw());
drop(class);
Ok(unsafe { JObject::from_raw(obj) })
}
#[allow(clippy::redundant_closure_call)]
fn get_method_id_base<'other_local_1, T, U, V, C, R>(
&mut self,
class: T,
name: U,
sig: V,
get_method: C,
) -> Result<R>
where
T: Desc<'local, JClass<'other_local_1>>,
U: Into<JNIString>,
V: Into<JNIString>,
C: for<'other_local_2> Fn(
&mut Self,
&JClass<'other_local_2>,
&JNIString,
&JNIString,
) -> Result<R>,
{
let class = class.lookup(self)?;
let ffi_name = name.into();
let sig = sig.into();
let res: Result<R> = catch!({ get_method(self, class.as_ref(), &ffi_name, &sig) });
match res {
Ok(m) => Ok(m),
Err(e) => match e {
Error::NullPtr(_) => {
let name: String = ffi_name.into();
let sig: String = sig.into();
Err(Error::MethodNotFound { name, sig })
}
_ => Err(e),
},
}
}
pub fn get_method_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JMethodID>
where
T: Desc<'local, JClass<'other_local>>,
U: Into<JNIString>,
V: Into<JNIString>,
{
self.get_method_id_base(class, name, sig, |env, class, name, sig| {
let method_id = jni_non_null_call!(
env.internal,
GetMethodID,
class.as_raw(),
name.as_ptr(),
sig.as_ptr()
);
Ok(unsafe { JMethodID::from_raw(method_id) })
})
}
pub fn get_static_method_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JStaticMethodID>
where
T: Desc<'local, JClass<'other_local>>,
U: Into<JNIString>,
V: Into<JNIString>,
{
self.get_method_id_base(class, name, sig, |env, class, name, sig| {
let method_id = jni_non_null_call!(
env.internal,
GetStaticMethodID,
class.as_raw(),
name.as_ptr(),
sig.as_ptr()
);
Ok(unsafe { JStaticMethodID::from_raw(method_id) })
})
}
pub fn get_field_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JFieldID>
where
T: Desc<'local, JClass<'other_local>>,
U: Into<JNIString>,
V: Into<JNIString>,
{
let class = class.lookup(self)?;
let ffi_name = name.into();
let ffi_sig = sig.into();
let res: Result<JFieldID> = catch!({
let field_id = jni_non_null_call!(
self.internal,
GetFieldID,
class.as_ref().as_raw(),
ffi_name.as_ptr(),
ffi_sig.as_ptr()
);
Ok(unsafe { JFieldID::from_raw(field_id) })
});
match res {
Ok(m) => Ok(m),
Err(e) => match e {
Error::NullPtr(_) => {
let name: String = ffi_name.into();
let sig: String = ffi_sig.into();
Err(Error::FieldNotFound { name, sig })
}
_ => Err(e),
},
}
}
pub fn get_static_field_id<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
) -> Result<JStaticFieldID>
where
T: Desc<'local, JClass<'other_local>>,
U: Into<JNIString>,
V: Into<JNIString>,
{
let class = class.lookup(self)?;
let ffi_name = name.into();
let ffi_sig = sig.into();
let res: Result<JStaticFieldID> = catch!({
let field_id = jni_non_null_call!(
self.internal,
GetStaticFieldID,
class.as_ref().as_raw(),
ffi_name.as_ptr(),
ffi_sig.as_ptr()
);
Ok(unsafe { JStaticFieldID::from_raw(field_id) })
});
drop(class);
match res {
Ok(m) => Ok(m),
Err(e) => match e {
Error::NullPtr(_) => {
let name: String = ffi_name.into();
let sig: String = ffi_sig.into();
Err(Error::FieldNotFound { name, sig })
}
_ => Err(e),
},
}
}
pub fn get_object_class<'other_local, O>(&self, obj: O) -> Result<JClass<'local>>
where
O: AsRef<JObject<'other_local>>,
{
let obj = obj.as_ref();
non_null!(obj, "get_object_class");
unsafe {
Ok(JClass::from_raw(jni_unchecked!(
self.internal,
GetObjectClass,
obj.as_raw()
)))
}
}
pub unsafe fn call_static_method_unchecked<'other_local, T, U>(
&mut self,
class: T,
method_id: U,
ret: ReturnType,
args: &[jvalue],
) -> Result<JValueOwned<'local>>
where
T: Desc<'local, JClass<'other_local>>,
U: Desc<'local, JStaticMethodID>,
{
let class = class.lookup(self)?;
let method_id = method_id.lookup(self)?.as_ref().into_raw();
let class_raw = class.as_ref().as_raw();
let jni_args = args.as_ptr();
let ret = Ok(match ret {
ReturnType::Object | ReturnType::Array => {
let obj = jni_non_void_call!(
self.internal,
CallStaticObjectMethodA,
class_raw,
method_id,
jni_args
);
let obj = unsafe { JObject::from_raw(obj) };
obj.into()
}
ReturnType::Primitive(p) => match p {
Primitive::Boolean => jni_non_void_call!(
self.internal,
CallStaticBooleanMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Char => jni_non_void_call!(
self.internal,
CallStaticCharMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Short => jni_non_void_call!(
self.internal,
CallStaticShortMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Int => jni_non_void_call!(
self.internal,
CallStaticIntMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Long => jni_non_void_call!(
self.internal,
CallStaticLongMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Float => jni_non_void_call!(
self.internal,
CallStaticFloatMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Double => jni_non_void_call!(
self.internal,
CallStaticDoubleMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Byte => jni_non_void_call!(
self.internal,
CallStaticByteMethodA,
class_raw,
method_id,
jni_args
)
.into(),
Primitive::Void => {
jni_void_call!(
self.internal,
CallStaticVoidMethodA,
class_raw,
method_id,
jni_args
);
return Ok(JValueOwned::Void);
}
}, });
drop(class);
ret
}
pub unsafe fn call_method_unchecked<'other_local, O, T>(
&mut self,
obj: O,
method_id: T,
ret: ReturnType,
args: &[jvalue],
) -> Result<JValueOwned<'local>>
where
O: AsRef<JObject<'other_local>>,
T: Desc<'local, JMethodID>,
{
let method_id = method_id.lookup(self)?.as_ref().into_raw();
let obj = obj.as_ref().as_raw();
let jni_args = args.as_ptr();
Ok(match ret {
ReturnType::Object | ReturnType::Array => {
let obj =
jni_non_void_call!(self.internal, CallObjectMethodA, obj, method_id, jni_args);
let obj = unsafe { JObject::from_raw(obj) };
obj.into()
}
ReturnType::Primitive(p) => match p {
Primitive::Boolean => {
jni_non_void_call!(self.internal, CallBooleanMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Char => {
jni_non_void_call!(self.internal, CallCharMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Short => {
jni_non_void_call!(self.internal, CallShortMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Int => {
jni_non_void_call!(self.internal, CallIntMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Long => {
jni_non_void_call!(self.internal, CallLongMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Float => {
jni_non_void_call!(self.internal, CallFloatMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Double => {
jni_non_void_call!(self.internal, CallDoubleMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Byte => {
jni_non_void_call!(self.internal, CallByteMethodA, obj, method_id, jni_args)
.into()
}
Primitive::Void => {
jni_void_call!(self.internal, CallVoidMethodA, obj, method_id, jni_args);
return Ok(JValueOwned::Void);
}
}, }) }
pub fn call_method<'other_local, O, S, T>(
&mut self,
obj: O,
name: S,
sig: T,
args: &[JValue],
) -> Result<JValueOwned<'local>>
where
O: AsRef<JObject<'other_local>>,
S: Into<JNIString>,
T: Into<JNIString> + AsRef<str>,
{
let obj = obj.as_ref();
non_null!(obj, "call_method obj argument");
let parsed = TypeSignature::from_str(sig.as_ref())?;
if parsed.args.len() != args.len() {
return Err(Error::InvalidArgList(parsed));
}
let base_types_match = parsed
.args
.iter()
.zip(args.iter())
.all(|(exp, act)| match exp {
JavaType::Primitive(p) => act.primitive_type() == Some(*p),
JavaType::Object(_) | JavaType::Array(_) => act.primitive_type().is_none(),
JavaType::Method(_) => {
unreachable!("JavaType::Method(_) should not come from parsing a method sig")
}
});
if !base_types_match {
return Err(Error::InvalidArgList(parsed));
}
let class = self.auto_local(self.get_object_class(obj)?);
let args: Vec<jvalue> = args.iter().map(|v| v.as_jni()).collect();
unsafe { self.call_method_unchecked(obj, (&class, name, sig), parsed.ret, &args) }
}
pub fn call_static_method<'other_local, T, U, V>(
&mut self,
class: T,
name: U,
sig: V,
args: &[JValue],
) -> Result<JValueOwned<'local>>
where
T: Desc<'local, JClass<'other_local>>,
U: Into<JNIString>,
V: Into<JNIString> + AsRef<str>,
{
let parsed = TypeSignature::from_str(&sig)?;
if parsed.args.len() != args.len() {
return Err(Error::InvalidArgList(parsed));
}
let base_types_match = parsed
.args
.iter()
.zip(args.iter())
.all(|(exp, act)| match exp {
JavaType::Primitive(p) => act.primitive_type() == Some(*p),
JavaType::Object(_) | JavaType::Array(_) => act.primitive_type().is_none(),
JavaType::Method(_) => {
unreachable!("JavaType::Method(_) should not come from parsing a method sig")
}
});
if !base_types_match {
return Err(Error::InvalidArgList(parsed));
}
let class = class.lookup(self)?;
let class = class.as_ref();
let args: Vec<jvalue> = args.iter().map(|v| v.as_jni()).collect();
unsafe { self.call_static_method_unchecked(class, (class, name, sig), parsed.ret, &args) }
}
pub fn new_object<'other_local, T, U>(
&mut self,
class: T,
ctor_sig: U,
ctor_args: &[JValue],
) -> Result<JObject<'local>>
where
T: Desc<'local, JClass<'other_local>>,
U: Into<JNIString> + AsRef<str>,
{
let parsed = TypeSignature::from_str(&ctor_sig)?;
if parsed.args.len() != ctor_args.len() {
return Err(Error::InvalidArgList(parsed));
}
let base_types_match =
parsed
.args
.iter()
.zip(ctor_args.iter())
.all(|(exp, act)| match exp {
JavaType::Primitive(p) => act.primitive_type() == Some(*p),
JavaType::Object(_) | JavaType::Array(_) => act.primitive_type().is_none(),
JavaType::Method(_) => {
unreachable!("JavaType::Method(_) should not come from parsing a ctor sig")
}
});
if !base_types_match {
return Err(Error::InvalidArgList(parsed));
}
if parsed.ret != ReturnType::Primitive(Primitive::Void) {
return Err(Error::InvalidCtorReturn);
}
let class = class.lookup(self)?;
let class = class.as_ref();
let method_id: JMethodID = Desc::<JMethodID>::lookup((class, ctor_sig), self)?;
let ctor_args: Vec<jvalue> = ctor_args.iter().map(|v| v.as_jni()).collect();
unsafe { self.new_object_unchecked(class, method_id, &ctor_args) }
}
pub unsafe fn new_object_unchecked<'other_local, T>(
&mut self,
class: T,
ctor_id: JMethodID,
ctor_args: &[jvalue],
) -> Result<JObject<'local>>
where
T: Desc<'local, JClass<'other_local>>,
{
let class = class.lookup(self)?;
let jni_args = ctor_args.as_ptr();
let obj = jni_non_null_call!(
self.internal,
NewObjectA,
class.as_ref().as_raw(),
ctor_id.into_raw(),
jni_args
);
drop(class);
Ok(unsafe { JObject::from_raw(obj) })
}
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>>
where
'other_local_1: 'obj_ref,
{
non_null!(obj, "get_list obj argument");
JList::from_env(self, obj)
}
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>>
where
'other_local_1: 'obj_ref,
{
non_null!(obj, "get_map obj argument");
JMap::from_env(self, obj)
}
pub unsafe fn get_string_unchecked<'other_local: 'obj_ref, 'obj_ref>(
&self,
obj: &'obj_ref JString<'other_local>,
) -> Result<JavaStr<'local, 'other_local, 'obj_ref>> {
non_null!(obj, "get_string obj argument");
JavaStr::from_env(self, obj)
}
pub fn get_string<'other_local: 'obj_ref, 'obj_ref>(
&mut self,
obj: &'obj_ref JString<'other_local>,
) -> Result<JavaStr<'local, 'other_local, 'obj_ref>> {
let string_class = self.find_class("java/lang/String")?;
if !self.is_assignable_from(string_class, self.get_object_class(obj)?)? {
return Err(JniCall(JniError::InvalidArguments));
}
unsafe { self.get_string_unchecked(obj) }
}
pub fn new_string<S: Into<JNIString>>(&self, from: S) -> Result<JString<'local>> {
let ffi_str = from.into();
let s = jni_non_null_call!(self.internal, NewStringUTF, ffi_str.as_ptr());
Ok(unsafe { JString::from_raw(s) })
}
pub fn get_array_length<'other_local, 'array>(
&self,
array: &'array impl AsJArrayRaw<'other_local>,
) -> Result<jsize> {
non_null!(array.as_jarray_raw(), "get_array_length array argument");
let len: jsize = jni_unchecked!(self.internal, GetArrayLength, array.as_jarray_raw());
Ok(len)
}
pub fn new_object_array<'other_local_1, 'other_local_2, T, U>(
&mut self,
length: jsize,
element_class: T,
initial_element: U,
) -> Result<JObjectArray<'local>>
where
T: Desc<'local, JClass<'other_local_2>>,
U: AsRef<JObject<'other_local_1>>,
{
let class = element_class.lookup(self)?;
let array: jarray = jni_non_null_call!(
self.internal,
NewObjectArray,
length,
class.as_ref().as_raw(),
initial_element.as_ref().as_raw()
);
let array = unsafe { JObjectArray::from_raw(array) };
drop(class);
Ok(array)
}
pub fn get_object_array_element<'other_local>(
&mut self,
array: impl AsRef<JObjectArray<'other_local>>,
index: jsize,
) -> Result<JObject<'local>> {
non_null!(array.as_ref(), "get_object_array_element array argument");
Ok(unsafe {
JObject::from_raw(jni_non_void_call!(
self.internal,
GetObjectArrayElement,
array.as_ref().as_raw(),
index
))
})
}
pub fn set_object_array_element<'other_local_1, 'other_local_2>(
&self,
array: impl AsRef<JObjectArray<'other_local_1>>,
index: jsize,
value: impl AsRef<JObject<'other_local_2>>,
) -> Result<()> {
non_null!(array.as_ref(), "set_object_array_element array argument");
jni_void_call!(
self.internal,
SetObjectArrayElement,
array.as_ref().as_raw(),
index,
value.as_ref().as_raw()
);
Ok(())
}
pub fn byte_array_from_slice(&self, buf: &[u8]) -> Result<JByteArray<'local>> {
let length = buf.len() as i32;
let bytes = self.new_byte_array(length)?;
jni_unchecked!(
self.internal,
SetByteArrayRegion,
bytes.as_raw(),
0,
length,
buf.as_ptr() as *const i8
);
Ok(bytes)
}
pub fn convert_byte_array<'other_local>(
&self,
array: impl AsRef<JByteArray<'other_local>>,
) -> Result<Vec<u8>> {
let array = array.as_ref().as_raw();
non_null!(array, "convert_byte_array array argument");
let length = jni_non_void_call!(self.internal, GetArrayLength, array);
let mut vec = vec![0u8; length as usize];
jni_unchecked!(
self.internal,
GetByteArrayRegion,
array,
0,
length,
vec.as_mut_ptr() as *mut i8
);
Ok(vec)
}
pub fn new_boolean_array(&self, length: jsize) -> Result<JBooleanArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewBooleanArray, length);
let array = unsafe { JBooleanArray::from_raw(array) };
Ok(array)
}
pub fn new_byte_array(&self, length: jsize) -> Result<JByteArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewByteArray, length);
let array = unsafe { JByteArray::from_raw(array) };
Ok(array)
}
pub fn new_char_array(&self, length: jsize) -> Result<JCharArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewCharArray, length);
let array = unsafe { JCharArray::from_raw(array) };
Ok(array)
}
pub fn new_short_array(&self, length: jsize) -> Result<JShortArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewShortArray, length);
let array = unsafe { JShortArray::from_raw(array) };
Ok(array)
}
pub fn new_int_array(&self, length: jsize) -> Result<JIntArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewIntArray, length);
let array = unsafe { JIntArray::from_raw(array) };
Ok(array)
}
pub fn new_long_array(&self, length: jsize) -> Result<JLongArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewLongArray, length);
let array = unsafe { JLongArray::from_raw(array) };
Ok(array)
}
pub fn new_float_array(&self, length: jsize) -> Result<JFloatArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewFloatArray, length);
let array = unsafe { JFloatArray::from_raw(array) };
Ok(array)
}
pub fn new_double_array(&self, length: jsize) -> Result<JDoubleArray<'local>> {
let array: jarray = jni_non_null_call!(self.internal, NewDoubleArray, length);
let array = unsafe { JDoubleArray::from_raw(array) };
Ok(array)
}
pub fn get_boolean_array_region<'other_local>(
&self,
array: impl AsRef<JBooleanArray<'other_local>>,
start: jsize,
buf: &mut [jboolean],
) -> Result<()> {
non_null!(array.as_ref(), "get_boolean_array_region array argument");
jni_void_call!(
self.internal,
GetBooleanArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn get_byte_array_region<'other_local>(
&self,
array: impl AsRef<JByteArray<'other_local>>,
start: jsize,
buf: &mut [jbyte],
) -> Result<()> {
non_null!(array.as_ref(), "get_byte_array_region array argument");
jni_void_call!(
self.internal,
GetByteArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn get_char_array_region<'other_local>(
&self,
array: impl AsRef<JCharArray<'other_local>>,
start: jsize,
buf: &mut [jchar],
) -> Result<()> {
non_null!(array.as_ref(), "get_char_array_region array argument");
jni_void_call!(
self.internal,
GetCharArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn get_short_array_region<'other_local>(
&self,
array: impl AsRef<JShortArray<'other_local>>,
start: jsize,
buf: &mut [jshort],
) -> Result<()> {
non_null!(array.as_ref(), "get_short_array_region array argument");
jni_void_call!(
self.internal,
GetShortArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn get_int_array_region<'other_local>(
&self,
array: impl AsRef<JIntArray<'other_local>>,
start: jsize,
buf: &mut [jint],
) -> Result<()> {
non_null!(array.as_ref(), "get_int_array_region array argument");
jni_void_call!(
self.internal,
GetIntArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn get_long_array_region<'other_local>(
&self,
array: impl AsRef<JLongArray<'other_local>>,
start: jsize,
buf: &mut [jlong],
) -> Result<()> {
non_null!(array.as_ref(), "get_long_array_region array argument");
jni_void_call!(
self.internal,
GetLongArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn get_float_array_region<'other_local>(
&self,
array: impl AsRef<JFloatArray<'other_local>>,
start: jsize,
buf: &mut [jfloat],
) -> Result<()> {
non_null!(array.as_ref(), "get_float_array_region array argument");
jni_void_call!(
self.internal,
GetFloatArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn get_double_array_region<'other_local>(
&self,
array: impl AsRef<JDoubleArray<'other_local>>,
start: jsize,
buf: &mut [jdouble],
) -> Result<()> {
non_null!(array.as_ref(), "get_double_array_region array argument");
jni_void_call!(
self.internal,
GetDoubleArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_mut_ptr()
);
Ok(())
}
pub fn set_boolean_array_region<'other_local>(
&self,
array: impl AsRef<JBooleanArray<'other_local>>,
start: jsize,
buf: &[jboolean],
) -> Result<()> {
non_null!(array.as_ref(), "set_boolean_array_region array argument");
jni_void_call!(
self.internal,
SetBooleanArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn set_byte_array_region<'other_local>(
&self,
array: impl AsRef<JByteArray<'other_local>>,
start: jsize,
buf: &[jbyte],
) -> Result<()> {
non_null!(array.as_ref(), "set_byte_array_region array argument");
jni_void_call!(
self.internal,
SetByteArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn set_char_array_region<'other_local>(
&self,
array: impl AsRef<JCharArray<'other_local>>,
start: jsize,
buf: &[jchar],
) -> Result<()> {
non_null!(array.as_ref(), "set_char_array_region array argument");
jni_void_call!(
self.internal,
SetCharArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn set_short_array_region<'other_local>(
&self,
array: impl AsRef<JShortArray<'other_local>>,
start: jsize,
buf: &[jshort],
) -> Result<()> {
non_null!(array.as_ref(), "set_short_array_region array argument");
jni_void_call!(
self.internal,
SetShortArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn set_int_array_region<'other_local>(
&self,
array: impl AsRef<JIntArray<'other_local>>,
start: jsize,
buf: &[jint],
) -> Result<()> {
non_null!(array.as_ref(), "set_int_array_region array argument");
jni_void_call!(
self.internal,
SetIntArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn set_long_array_region<'other_local>(
&self,
array: impl AsRef<JLongArray<'other_local>>,
start: jsize,
buf: &[jlong],
) -> Result<()> {
non_null!(array.as_ref(), "set_long_array_region array argument");
jni_void_call!(
self.internal,
SetLongArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn set_float_array_region<'other_local>(
&self,
array: impl AsRef<JFloatArray<'other_local>>,
start: jsize,
buf: &[jfloat],
) -> Result<()> {
non_null!(array.as_ref(), "set_float_array_region array argument");
jni_void_call!(
self.internal,
SetFloatArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn set_double_array_region<'other_local>(
&self,
array: impl AsRef<JDoubleArray<'other_local>>,
start: jsize,
buf: &[jdouble],
) -> Result<()> {
non_null!(array.as_ref(), "set_double_array_region array argument");
jni_void_call!(
self.internal,
SetDoubleArrayRegion,
array.as_ref().as_raw(),
start,
buf.len() as jsize,
buf.as_ptr()
);
Ok(())
}
pub fn get_field_unchecked<'other_local, O, T>(
&mut self,
obj: O,
field: T,
ty: ReturnType,
) -> Result<JValueOwned<'local>>
where
O: AsRef<JObject<'other_local>>,
T: Desc<'local, JFieldID>,
{
let obj = obj.as_ref();
non_null!(obj, "get_field_typed obj argument");
let field = field.lookup(self)?.as_ref().into_raw();
let obj = obj.as_raw();
Ok(match ty {
ReturnType::Object | ReturnType::Array => {
let obj = jni_non_void_call!(self.internal, GetObjectField, obj, field);
let obj = unsafe { JObject::from_raw(obj) };
obj.into()
}
ReturnType::Primitive(p) => match p {
Primitive::Boolean => {
jni_unchecked!(self.internal, GetBooleanField, obj, field).into()
}
Primitive::Char => jni_unchecked!(self.internal, GetCharField, obj, field).into(),
Primitive::Short => jni_unchecked!(self.internal, GetShortField, obj, field).into(),
Primitive::Int => jni_unchecked!(self.internal, GetIntField, obj, field).into(),
Primitive::Long => jni_unchecked!(self.internal, GetLongField, obj, field).into(),
Primitive::Float => jni_unchecked!(self.internal, GetFloatField, obj, field).into(),
Primitive::Double => {
jni_unchecked!(self.internal, GetDoubleField, obj, field).into()
}
Primitive::Byte => jni_unchecked!(self.internal, GetByteField, obj, field).into(),
Primitive::Void => {
return Err(Error::WrongJValueType("void", "see java field"));
}
},
})
}
pub fn set_field_unchecked<'other_local, O, T>(
&mut self,
obj: O,
field: T,
val: JValue,
) -> Result<()>
where
O: AsRef<JObject<'other_local>>,
T: Desc<'local, JFieldID>,
{
let obj = obj.as_ref();
non_null!(obj, "set_field_typed obj argument");
let field = field.lookup(self)?.as_ref().into_raw();
let obj = obj.as_raw();
match val {
JValue::Object(o) => {
jni_unchecked!(self.internal, SetObjectField, obj, field, o.as_raw());
}
JValue::Bool(b) => {
jni_unchecked!(self.internal, SetBooleanField, obj, field, b);
}
JValue::Char(c) => {
jni_unchecked!(self.internal, SetCharField, obj, field, c);
}
JValue::Short(s) => {
jni_unchecked!(self.internal, SetShortField, obj, field, s);
}
JValue::Int(i) => {
jni_unchecked!(self.internal, SetIntField, obj, field, i);
}
JValue::Long(l) => {
jni_unchecked!(self.internal, SetLongField, obj, field, l);
}
JValue::Float(f) => {
jni_unchecked!(self.internal, SetFloatField, obj, field, f);
}
JValue::Double(d) => {
jni_unchecked!(self.internal, SetDoubleField, obj, field, d);
}
JValue::Byte(b) => {
jni_unchecked!(self.internal, SetByteField, obj, field, b);
}
JValue::Void => {
return Err(Error::WrongJValueType("void", "see java field"));
}
};
Ok(())
}
pub fn get_field<'other_local, O, S, T>(
&mut self,
obj: O,
name: S,
ty: T,
) -> Result<JValueOwned<'local>>
where
O: AsRef<JObject<'other_local>>,
S: Into<JNIString>,
T: Into<JNIString> + AsRef<str>,
{
let obj = obj.as_ref();
let class = self.auto_local(self.get_object_class(obj)?);
let parsed = ReturnType::from_str(ty.as_ref())?;
let field_id: JFieldID = Desc::<JFieldID>::lookup((&class, name, ty), self)?;
self.get_field_unchecked(obj, field_id, parsed)
}
pub fn set_field<'other_local, O, S, T>(
&mut self,
obj: O,
name: S,
ty: T,
val: JValue,
) -> Result<()>
where
O: AsRef<JObject<'other_local>>,
S: Into<JNIString>,
T: Into<JNIString> + AsRef<str>,
{
let obj = obj.as_ref();
let parsed = JavaType::from_str(ty.as_ref())?;
let in_type = val.primitive_type();
match parsed {
JavaType::Object(_) | JavaType::Array(_) => {
if in_type.is_some() {
return Err(Error::WrongJValueType(val.type_name(), "see java field"));
}
}
JavaType::Primitive(p) => {
if let Some(in_p) = in_type {
if in_p == p {
} else {
return Err(Error::WrongJValueType(val.type_name(), "see java field"));
}
} else {
return Err(Error::WrongJValueType(val.type_name(), "see java field"));
}
}
JavaType::Method(_) => unimplemented!(),
}
let class = self.auto_local(self.get_object_class(obj)?);
self.set_field_unchecked(obj, (&class, name, ty), val)
}
pub fn get_static_field_unchecked<'other_local, T, U>(
&mut self,
class: T,
field: U,
ty: JavaType,
) -> Result<JValueOwned<'local>>
where
T: Desc<'local, JClass<'other_local>>,
U: Desc<'local, JStaticFieldID>,
{
use JavaType::Primitive as JP;
let class = class.lookup(self)?;
let field = field.lookup(self)?;
let result = match ty {
JavaType::Object(_) | JavaType::Array(_) => {
let obj = jni_non_void_call!(
self.internal,
GetStaticObjectField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
);
let obj = unsafe { JObject::from_raw(obj) };
obj.into()
}
JavaType::Method(_) => return Err(Error::WrongJValueType("Method", "see java field")),
JP(Primitive::Boolean) => jni_unchecked!(
self.internal,
GetStaticBooleanField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Char) => jni_unchecked!(
self.internal,
GetStaticCharField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Short) => jni_unchecked!(
self.internal,
GetStaticShortField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Int) => jni_unchecked!(
self.internal,
GetStaticIntField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Long) => jni_unchecked!(
self.internal,
GetStaticLongField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Float) => jni_unchecked!(
self.internal,
GetStaticFloatField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Double) => jni_unchecked!(
self.internal,
GetStaticDoubleField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Byte) => jni_unchecked!(
self.internal,
GetStaticByteField,
class.as_ref().as_raw(),
field.as_ref().into_raw()
)
.into(),
JP(Primitive::Void) => return Err(Error::WrongJValueType("void", "see java field")),
};
drop(class);
Ok(result)
}
pub fn get_static_field<'other_local, T, U, V>(
&mut self,
class: T,
field: U,
sig: V,
) -> Result<JValueOwned<'local>>
where
T: Desc<'local, JClass<'other_local>>,
U: Into<JNIString>,
V: Into<JNIString> + AsRef<str>,
{
let ty = JavaType::from_str(sig.as_ref())?;
let class = class.lookup(self)?;
self.get_static_field_unchecked(class.as_ref(), (class.as_ref(), field, sig), ty)
}
pub fn set_static_field<'other_local, T, U>(
&mut self,
class: T,
field: U,
value: JValue,
) -> Result<()>
where
T: Desc<'local, JClass<'other_local>>,
U: Desc<'local, JStaticFieldID>,
{
let class = class.lookup(self)?;
let field = field.lookup(self)?;
match value {
JValue::Object(v) => jni_unchecked!(
self.internal,
SetStaticObjectField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v.as_raw()
),
JValue::Byte(v) => jni_unchecked!(
self.internal,
SetStaticByteField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
),
JValue::Char(v) => jni_unchecked!(
self.internal,
SetStaticCharField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
),
JValue::Short(v) => jni_unchecked!(
self.internal,
SetStaticShortField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
),
JValue::Int(v) => jni_unchecked!(
self.internal,
SetStaticIntField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
),
JValue::Long(v) => jni_unchecked!(
self.internal,
SetStaticLongField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
),
JValue::Bool(v) => {
jni_unchecked!(
self.internal,
SetStaticBooleanField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
)
}
JValue::Float(v) => jni_unchecked!(
self.internal,
SetStaticFloatField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
),
JValue::Double(v) => {
jni_unchecked!(
self.internal,
SetStaticDoubleField,
class.as_ref().as_raw(),
field.as_ref().into_raw(),
v
)
}
JValue::Void => return Err(Error::WrongJValueType("void", "?")),
}
drop(class);
Ok(())
}
#[allow(unused_variables)]
pub unsafe fn set_rust_field<'other_local, O, S, T>(
&mut self,
obj: O,
field: S,
rust_object: T,
) -> Result<()>
where
O: AsRef<JObject<'other_local>>,
S: AsRef<str>,
T: Send + 'static,
{
let obj = obj.as_ref();
let class = self.auto_local(self.get_object_class(obj)?);
let field_id: JFieldID = Desc::<JFieldID>::lookup((&class, &field, "J"), self)?;
let guard = self.lock_obj(obj)?;
let field_ptr = self
.get_field_unchecked(obj, field_id, ReturnType::Primitive(Primitive::Long))?
.j()? as *mut Mutex<T>;
if !field_ptr.is_null() {
return Err(Error::FieldAlreadySet(field.as_ref().to_owned()));
}
let mbox = Box::new(::std::sync::Mutex::new(rust_object));
let ptr: *mut Mutex<T> = Box::into_raw(mbox);
self.set_field_unchecked(obj, field_id, (ptr as crate::sys::jlong).into())
}
#[allow(unused_variables)]
pub unsafe fn get_rust_field<'other_local, O, S, T>(
&mut self,
obj: O,
field: S,
) -> Result<MutexGuard<T>>
where
O: AsRef<JObject<'other_local>>,
S: Into<JNIString>,
T: Send + 'static,
{
let obj = obj.as_ref();
let guard = self.lock_obj(obj)?;
let ptr = self.get_field(obj, field, "J")?.j()? as *mut Mutex<T>;
non_null!(ptr, "rust value from Java");
Ok((*ptr).lock().unwrap())
}
#[allow(unused_variables)]
pub unsafe fn take_rust_field<'other_local, O, S, T>(&mut self, obj: O, field: S) -> Result<T>
where
O: AsRef<JObject<'other_local>>,
S: AsRef<str>,
T: Send + 'static,
{
let obj = obj.as_ref();
let class = self.auto_local(self.get_object_class(obj)?);
let field_id: JFieldID = Desc::<JFieldID>::lookup((&class, &field, "J"), self)?;
let mbox = {
let guard = self.lock_obj(obj)?;
let ptr = self
.get_field_unchecked(obj, field_id, ReturnType::Primitive(Primitive::Long))?
.j()? as *mut Mutex<T>;
non_null!(ptr, "rust value from Java");
let mbox = Box::from_raw(ptr);
drop(mbox.try_lock()?);
self.set_field_unchecked(
obj,
field_id,
(::std::ptr::null_mut::<()>() as sys::jlong).into(),
)?;
mbox
};
Ok(mbox.into_inner().unwrap())
}
pub fn lock_obj<'other_local, O>(&self, obj: O) -> Result<MonitorGuard<'local>>
where
O: AsRef<JObject<'other_local>>,
{
let inner = obj.as_ref().as_raw();
let _ = jni_unchecked!(self.internal, MonitorEnter, inner);
Ok(MonitorGuard {
obj: inner,
env: self.internal,
life: Default::default(),
})
}
pub fn get_native_interface(&self) -> *mut sys::JNIEnv {
self.internal
}
pub fn get_java_vm(&self) -> Result<JavaVM> {
let mut raw = ptr::null_mut();
let res = jni_unchecked!(self.internal, GetJavaVM, &mut raw);
jni_error_code_to_result(res)?;
unsafe { JavaVM::from_raw(raw) }
}
pub fn ensure_local_capacity(&self, capacity: jint) -> Result<()> {
jni_void_call!(self.internal, EnsureLocalCapacity, capacity);
Ok(())
}
pub fn register_native_methods<'other_local, T>(
&mut self,
class: T,
methods: &[NativeMethod],
) -> Result<()>
where
T: Desc<'local, JClass<'other_local>>,
{
let class = class.lookup(self)?;
let jni_native_methods: Vec<JNINativeMethod> = methods
.iter()
.map(|nm| JNINativeMethod {
name: nm.name.as_ptr() as *mut c_char,
signature: nm.sig.as_ptr() as *mut c_char,
fnPtr: nm.fn_ptr,
})
.collect();
let res = jni_non_void_call!(
self.internal,
RegisterNatives,
class.as_ref().as_raw(),
jni_native_methods.as_ptr(),
jni_native_methods.len() as jint
);
drop(class);
jni_error_code_to_result(res)
}
pub fn unregister_native_methods<'other_local, T>(&mut self, class: T) -> Result<()>
where
T: Desc<'local, JClass<'other_local>>,
{
let class = class.lookup(self)?;
let res = jni_non_void_call!(self.internal, UnregisterNatives, class.as_ref().as_raw());
drop(class);
jni_error_code_to_result(res)
}
pub unsafe fn get_array_elements<'other_local, 'array, T: TypeArray>(
&mut self,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<AutoElements<'local, 'other_local, 'array, T>> {
non_null!(array, "get_array_elements array argument");
AutoElements::new(self, array, mode)
}
pub unsafe fn get_array_elements_critical<'other_local, 'array, 'env, T: TypeArray>(
&'env mut self,
array: &'array JPrimitiveArray<'other_local, T>,
mode: ReleaseMode,
) -> Result<AutoElementsCritical<'local, 'other_local, 'array, 'env, T>> {
non_null!(array, "get_primitive_array_critical array argument");
AutoElementsCritical::new(self, array, mode)
}
}
pub struct NativeMethod {
pub name: JNIString,
pub sig: JNIString,
pub fn_ptr: *mut c_void,
}
pub struct MonitorGuard<'local> {
obj: sys::jobject,
env: *mut sys::JNIEnv,
life: PhantomData<&'local ()>,
}
impl<'local> Drop for MonitorGuard<'local> {
fn drop(&mut self) {
let res: Result<()> = catch!({
jni_unchecked!(self.env, MonitorExit, self.obj);
Ok(())
});
if let Err(e) = res {
warn!("error releasing java monitor: {}", e)
}
}
}