uni_jnihelpers/
macroses.rs

1#[derive(Copy, Clone)]
2#[doc(hidden)]
3pub struct JMethodIDHack {
4	pub jmethodid: jni::sys::jmethodID,
5}
6
7unsafe impl Send for JMethodIDHack {
8}
9unsafe impl Sync for JMethodIDHack {
10}
11
12/// At the point of instantiaction the macros creates global cache to
13/// access java class by name.
14///
15/// ```
16/// let class: Result<jni::objects::JClass<'static>, uni_jnihelpers::JniError>;
17/// class = get_java_class!(jni_env, "my/class/full/Name");
18/// ```
19#[macro_export]
20macro_rules! get_java_class {
21	($env:expr, $class_name:expr) => {{
22		use $crate::{
23			reimport::{
24				jni::objects::JClass,
25				parking_lot::{
26					const_rwlock,
27					RwLock,
28				},
29			},
30			JniError,
31			UniGlobalRef as UGR,
32			};
33
34		static CACHE: RwLock<Option<UGR<JClass<'static>>>> = const_rwlock(None);
35
36		let read_lock = CACHE.read();
37		let result = match read_lock.as_ref() {
38			Some(bc) => Ok(bc.clone()),
39			None => {
40				std::mem::drop(read_lock);
41				match $env.find_class($class_name) {
42					Err(e) => Err(JniError::JniError(e)),
43					Ok(class) => {
44						let class: JClass<'static> = class.into_inner().into();
45						match UGR::try_new($env, class) {
46							Err(e) => Err(e),
47							Ok(class) => {
48								*CACHE.write() = Some(class.clone());
49								Ok(class)
50							},
51						}
52					},
53				}
54			},
55			};
56
57		result
58		}};
59}
60
61
62/// At the point of instantiaction the macros creates global cache to
63/// access java method by name.
64///
65/// ```
66/// let method: jni::sys::jmethodID = get_java_method!(
67///     jni_env,
68///     class_ref,  // jni::objects::JClass
69///     "methodName",
70///     "(Lmethod;Lsignature;)V"
71/// )?;
72/// ```
73#[macro_export]
74macro_rules! get_java_method {
75	($env:expr, $class:expr, $method_name:expr, $method_signature:expr) => {{
76		use $crate::{
77			macroses::JMethodIDHack,
78			reimport::{
79				jni::objects::JMethodID,
80				parking_lot::{
81					const_rwlock,
82					RwLock,
83				},
84			},
85			};
86
87		static CACHE: RwLock<Option<JMethodIDHack>> = const_rwlock(None);
88
89		let method = CACHE.read();
90		let jmethodid = match method.as_ref() {
91			Some(method) => method.jmethodid,
92			None => {
93				std::mem::drop(method);
94				let maybe_method =
95					$env.get_method_id($class, $method_name, $method_signature);
96				let method = match maybe_method {
97					Ok(method) => method,
98					Err(e) => {
99						$crate::reimport::log::error!("get_method err:{:?}", e);
100						// We call it one more time to allow Java to print stack trace for
101						// potential exception
102						let _ =
103							$env.get_method_id($class, $method_name, $method_signature);
104						panic!("get_method failed");
105					},
106				};
107
108				let method = JMethodIDHack {
109					jmethodid: method.into_inner(),
110				};
111
112				*CACHE.write() = Some(method);
113				method.jmethodid
114			},
115			};
116
117		JMethodID::from(jmethodid)
118		}};
119}
120
121/// At the point of instantiaction the macros creates global cache to
122/// access java static method by name.
123///
124/// ```
125/// let method: jni::sys::jmethodID = get_java_static_method!(
126///     jni_env,
127///     class_ref,  // jni::objects::JClass
128///     "methodName",
129///     "(Lmethod;Lsignature;)V"
130/// )?;
131/// ```
132#[macro_export]
133macro_rules! get_java_static_method {
134	($env:expr, $class:expr, $method_name:expr, $method_signature:expr) => {{
135		use $crate::{
136			macroses::JMethodIDHack,
137			reimport::{
138				jni::objects::JStaticMethodID,
139				parking_lot::{
140					const_rwlock,
141					RwLock,
142				},
143			},
144			};
145
146		static CACHE: RwLock<Option<JMethodIDHack>> = const_rwlock(None);
147
148		let method = CACHE.read();
149		let jmethodid = match method.as_ref() {
150			Some(method) => method.jmethodid,
151			None => {
152				std::mem::drop(method);
153				let maybe_method =
154					$env.get_static_method_id($class, $method_name, $method_signature);
155				let method = match maybe_method {
156					Ok(method) => method,
157					Err(e) => {
158						$crate::reimport::log::error!("get_method err:{:?}", e);
159						// We call it one more time to allow Java to print stack trace for
160						// potential exception
161						let _ = $env.get_static_method_id(
162							$class,
163							$method_name,
164							$method_signature,
165						);
166						panic!("get_method failed");
167					},
168				};
169
170				let method = JMethodIDHack {
171					jmethodid: method.into_inner(),
172				};
173
174				*CACHE.write() = Some(method);
175				method.jmethodid
176			},
177			};
178
179		JStaticMethodID::from(jmethodid)
180		}};
181}