1use std::mem;
16use std::os::raw::{c_char, c_double};
17use std::ptr;
18
19use jni_sys::{jint, jobject, jobjectRefType, jstring, JNIEnv, JNI_TRUE};
20
21use crate::cache;
22use crate::errors;
23use crate::errors::opt_to_res;
24use crate::logger::{debug, error};
25use crate::utils;
26use crate::{InvocationArg, Jvm};
27
28pub(crate) fn invocation_arg_jobject_from_rust_serialized(
29 ia: &InvocationArg,
30 jni_env: *mut JNIEnv,
31 create_global: bool,
32) -> errors::Result<jobject> {
33 unsafe {
34 let (class_name, json) = match ia {
35 _s @ &InvocationArg::Java { .. } | _s @ &InvocationArg::RustBasic { .. } => {
36 panic!("Called invocation_arg_jobject_from_rust_serialized for an InvocationArg that contains an object. Please consider opening a bug to the developers.")
37 }
38 InvocationArg::Rust {
39 class_name,
40 json,
41 ..
42 } => {
43 debug(&format!(
44 "Creating jobject from Rust with serialized representation for class {}",
45 class_name
46 ));
47 (class_name.to_owned(), json.to_owned())
48 }
49 };
50
51 let class_name_jstring = global_jobject_from_str(&class_name, jni_env)?;
52 let json_jstring = global_jobject_from_str(&json, jni_env)?;
53
54 debug(&format!(
55 "Calling the InvocationArg constructor with '{}'",
56 class_name
57 ));
58 let inv_arg_instance = (opt_to_res(cache::get_jni_new_object())?)(
59 jni_env,
60 cache::get_invocation_arg_class()?,
61 cache::get_inv_arg_rust_constructor_method()?,
62 class_name_jstring,
64 json_jstring,
66 );
67
68 Jvm::do_return(jni_env, ())?;
70 delete_java_ref(jni_env, class_name_jstring);
71 delete_java_ref(jni_env, json_jstring);
72
73 if create_global {
74 Ok(create_global_ref_from_local_ref(inv_arg_instance, jni_env)?)
75 } else {
76 Ok(inv_arg_instance)
77 }
78 }
79}
80
81pub(crate) fn invocation_arg_jobject_from_rust_basic(
82 ia: &InvocationArg,
83 jni_env: *mut JNIEnv,
84 create_global: bool,
85) -> errors::Result<jobject> {
86 unsafe {
87 let (class_name, jinstance) = match ia {
88 _s @ &InvocationArg::Java { .. } => {
89 panic!("Called invocation_arg_jobject_from_rust_basic for an InvocationArg that contains an object from Java. Please consider opening a bug to the developers.")
90 }
91 _s @ &InvocationArg::Rust { .. } => {
92 panic!("Called invocation_arg_jobject_from_rust_basic for an InvocationArg that contains a serialized object. Please consider opening a bug to the developers.")
93 }
94 InvocationArg::RustBasic {
95 class_name,
96 instance,
97 ..
98 } => {
99 debug(&format!(
100 "Creating jobject from Rust basic for class {}",
101 class_name
102 ));
103 (class_name.to_owned(), instance.jinstance)
104 }
105 };
106 debug(&format!(
107 "Calling the InvocationArg constructor with '{}'",
108 class_name
109 ));
110 let class_name_jstring = global_jobject_from_str(&class_name, jni_env)?;
111
112 let inv_arg_instance = (opt_to_res(cache::get_jni_new_object())?)(
113 jni_env,
114 cache::get_invocation_arg_class()?,
115 cache::get_inv_arg_basic_rust_constructor_method()?,
116 class_name_jstring,
118 jinstance,
120 );
121
122 delete_java_ref(jni_env, class_name_jstring);
123
124 if create_global {
125 Ok(create_global_ref_from_local_ref(inv_arg_instance, jni_env)?)
126 } else {
127 Ok(inv_arg_instance)
128 }
129 }
130}
131
132pub(crate) fn invocation_arg_jobject_from_java(
133 ia: &InvocationArg,
134 jni_env: *mut JNIEnv,
135 create_global: bool,
136) -> errors::Result<jobject> {
137 unsafe {
138 let (class_name, jinstance) = match ia {
139 _s @ &InvocationArg::Rust { .. } => panic!("Called invocation_arg_jobject_from_java for an InvocationArg that is created by Rust. Please consider opening a bug to the developers."),
140 &InvocationArg::Java { ref class_name, ref instance, .. } | &InvocationArg::RustBasic { ref class_name, ref instance, .. } => {
141 debug(&format!("Creating jobject from Java for class {}", class_name));
142 (class_name.to_owned(), instance.jinstance)
143 }
144 };
145
146 debug(&format!(
147 "Calling the InvocationArg constructor for class '{}'",
148 class_name
149 ));
150
151 let class_name_jstring = global_jobject_from_str(&class_name, jni_env)?;
152
153 let inv_arg_instance = (opt_to_res(cache::get_jni_new_object())?)(
154 jni_env,
155 cache::get_invocation_arg_class()?,
156 cache::get_inv_arg_java_constructor_method()?,
157 class_name_jstring,
159 jinstance,
161 );
162
163 Jvm::do_return(jni_env, ())?;
165 delete_java_ref(jni_env, class_name_jstring);
166
167 if create_global {
168 Ok(create_global_ref_from_local_ref(inv_arg_instance, jni_env)?)
169 } else {
170 Ok(inv_arg_instance)
171 }
172 }
173}
174
175pub fn create_global_ref_from_local_ref(
176 local_ref: jobject,
177 jni_env: *mut JNIEnv,
178) -> errors::Result<jobject> {
179 unsafe {
180 let ngr = (**jni_env).v1_6.NewGlobalRef;
181 let exc = (**jni_env).v1_6.ExceptionCheck;
182 let exd = (**jni_env).v1_6.ExceptionDescribe;
183 let exclear = (**jni_env).v1_6.ExceptionClear;
184 let gort = (**jni_env).v1_6.GetObjectRefType;
185 let global = ngr(
187 jni_env,
188 local_ref,
189 );
190 if gort(jni_env, local_ref) as jint == jobjectRefType::JNILocalRefType as jint {
192 delete_java_local_ref(jni_env, local_ref);
193 }
194 if (exc)(jni_env) == JNI_TRUE {
196 (exd)(jni_env);
197 (exclear)(jni_env);
198 Err(errors::J4RsError::JavaError("An Exception was thrown by Java while creating global ref... Please check the logs or the console.".to_string()))
199 } else {
200 Ok(global)
201 }
202 }
203}
204
205pub(crate) fn _create_weak_global_ref_from_global_ref(
206 global_ref: jobject,
207 jni_env: *mut JNIEnv,
208) -> errors::Result<jobject> {
209 unsafe {
210 let nwgr = (**jni_env).v1_6.NewWeakGlobalRef;
211 let exc = (**jni_env).v1_6.ExceptionCheck;
212 let exd = (**jni_env).v1_6.ExceptionDescribe;
213 let exclear = (**jni_env).v1_6.ExceptionClear;
214
215 let global = nwgr(jni_env, global_ref);
217 if (exc)(jni_env) == JNI_TRUE {
219 (exd)(jni_env);
220 (exclear)(jni_env);
221 Err(errors::J4RsError::JavaError("An Exception was thrown by Java while creating a weak global ref... Please check the logs or the console.".to_string()))
222 } else {
223 Ok(global)
224 }
225 }
226}
227
228pub fn delete_java_ref(jni_env: *mut JNIEnv, jinstance: jobject) {
230 unsafe {
231 let dgr = (**jni_env).v1_6.DeleteGlobalRef;
232 let exc = (**jni_env).v1_6.ExceptionCheck;
233 let exd = (**jni_env).v1_6.ExceptionDescribe;
234 let exclear = (**jni_env).v1_6.ExceptionClear;
235 dgr(jni_env, jinstance);
236 if (exc)(jni_env) == JNI_TRUE {
237 (exd)(jni_env);
238 (exclear)(jni_env);
239 error(
240 "An Exception was thrown by Java... Please check the logs or the console.",
241 );
242 }
243 }
244}
245
246pub(crate) fn delete_java_local_ref(jni_env: *mut JNIEnv, jinstance: jobject) {
248 unsafe {
249 let dlr = (**jni_env).v1_6.DeleteLocalRef;
250 let exc = (**jni_env).v1_6.ExceptionCheck;
251 let exd = (**jni_env).v1_6.ExceptionDescribe;
252 let exclear = (**jni_env).v1_6.ExceptionClear;
253 dlr(jni_env, jinstance);
254 if (exc)(jni_env) == JNI_TRUE {
255 (exd)(jni_env);
256 (exclear)(jni_env);
257 error(
258 "An Exception was thrown by Java... Please check the logs or the console.",
259 );
260 }
261 }
262}
263
264pub(crate) fn global_jobject_from_str(
265 string: &str,
266 jni_env: *mut JNIEnv,
267) -> errors::Result<jobject> {
268 let obj = local_jobject_from_str(string, jni_env)?;
269 let gr = create_global_ref_from_local_ref(obj, jni_env)?;
270 Ok(gr)
271}
272
273pub(crate) fn local_jobject_from_str(
274 string: &str,
275 jni_env: *mut JNIEnv,
276) -> errors::Result<jobject> {
277 unsafe {
278 let tmp = utils::to_c_string_struct(string);
279 Ok((opt_to_res(cache::get_jni_new_string_utf())?)(jni_env, tmp.as_ptr()))
280 }
281}
282
283pub(crate) fn global_jobject_from_i8(a: &i8, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
284 unsafe {
285 let tmp = *a as *const i8;
286 let o = (opt_to_res(cache::get_jni_new_object())?)(
287 jni_env,
288 cache::get_byte_class()?,
289 cache::get_byte_constructor_method()?,
290 tmp as *const i8,
291 );
292 create_global_ref_from_local_ref(o, jni_env)
293 }
294}
295
296pub(crate) unsafe fn i8_from_jobject(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<i8> {
297 if obj.is_null() {
298 Err(errors::J4RsError::JniError(
299 "Attempt to create an i8 from null".to_string(),
300 ))
301 } else {
302 let v = (opt_to_res(cache::get_jni_call_byte_method())?)(
303 jni_env,
304 obj,
305 cache::get_byte_to_byte_method()?,
306 );
307 Ok(v as i8)
308 }
309}
310
311pub(crate) fn global_jobject_from_i16(a: &i16, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
312 unsafe {
313 let tmp = *a as *const i16;
314 let o = (opt_to_res(cache::get_jni_new_object())?)(
315 jni_env,
316 cache::get_short_class()?,
317 cache::get_short_constructor_method()?,
318 tmp as *const i16,
319 );
320 create_global_ref_from_local_ref(o, jni_env)
321 }
322}
323
324pub(crate) fn global_jobject_from_u16(a: &u16, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
325 unsafe {
326 let tmp = *a as *const u16;
327 let o = (opt_to_res(cache::get_jni_new_object())?)(
328 jni_env,
329 cache::get_character_class()?,
330 cache::get_character_constructor_method()?,
331 tmp as *const u16,
332 );
333 create_global_ref_from_local_ref(o, jni_env)
334 }
335}
336
337pub(crate) unsafe fn i16_from_jobject(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<i16> {
338 if obj.is_null() {
339 Err(errors::J4RsError::JniError(
340 "Attempt to create an i16 from null".to_string(),
341 ))
342 } else {
343 let v = (opt_to_res(cache::get_jni_call_short_method())?)(
344 jni_env,
345 obj,
346 cache::get_short_to_short_method()?,
347 );
348 Ok(v as i16)
349 }
350}
351
352pub(crate) unsafe fn u16_from_jobject(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<u16> {
353 if obj.is_null() {
354 Err(errors::J4RsError::JniError(
355 "Attempt to create an u16 from null".to_string(),
356 ))
357 } else {
358 let v = (opt_to_res(cache::get_jni_call_char_method())?)(
359 jni_env,
360 obj,
361 cache::get_character_to_char_method()?,
362 );
363 Ok(v as u16)
364 }
365}
366
367pub(crate) fn global_jobject_from_i32(a: &i32, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
368 unsafe {
369 let tmp = *a as *const i32;
370 let o = (opt_to_res(cache::get_jni_new_object())?)(
371 jni_env,
372 cache::get_integer_class()?,
373 cache::get_integer_constructor_method()?,
374 tmp as *const i32,
375 );
376 create_global_ref_from_local_ref(o, jni_env)
377 }
378}
379
380pub(crate) unsafe fn i32_from_jobject(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<i32> {
381 if obj.is_null() {
382 Err(errors::J4RsError::JniError(
383 "Attempt to create an i32 from null".to_string(),
384 ))
385 } else {
386 let v = (opt_to_res(cache::get_jni_call_int_method())?)(
387 jni_env,
388 obj,
389 cache::get_integer_to_int_method()?,
390 );
391 Ok(v as i32)
392 }
393}
394
395pub(crate) fn global_jobject_from_i64(a: &i64, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
396 unsafe {
397 let tmp = *a;
398 let o = (opt_to_res(cache::get_jni_new_object())?)(
399 jni_env,
400 cache::get_long_class()?,
401 cache::get_long_constructor_method()?,
402 tmp as *const i64,
403 );
404 create_global_ref_from_local_ref(o, jni_env)
405 }
406}
407
408pub(crate) unsafe fn i64_from_jobject(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<i64> {
409 if obj.is_null() {
410 Err(errors::J4RsError::JniError(
411 "Attempt to create an i64 from null".to_string(),
412 ))
413 } else {
414 let v = (opt_to_res(cache::get_jni_call_long_method())?)(
415 jni_env,
416 obj,
417 cache::get_long_to_long_method()?,
418 );
419 Ok(v as i64)
420 }
421}
422
423pub(crate) fn global_jobject_from_f32(a: &f32, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
424 let tmp = *a;
425 unsafe {
426 let o = (opt_to_res(cache::get_jni_new_object())?)(
427 jni_env,
428 cache::get_float_class()?,
429 cache::get_float_constructor_method()?,
430 tmp as c_double,
431 );
432 create_global_ref_from_local_ref(o, jni_env)
433 }
434}
435
436pub(crate) unsafe fn f32_from_jobject(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<f32> {
437 if obj.is_null() {
438 Err(errors::J4RsError::JniError(
439 "Attempt to create an f32 from null".to_string(),
440 ))
441 } else {
442 let v = (opt_to_res(cache::get_jni_call_float_method())?)(
443 jni_env,
444 obj,
445 cache::get_float_to_float_method()?,
446 );
447 Ok(v)
448 }
449}
450
451pub(crate) fn global_jobject_from_f64(a: &f64, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
452 let tmp = *a;
453 unsafe {
454 let o = (opt_to_res(cache::get_jni_new_object())?)(
455 jni_env,
456 cache::get_double_class()?,
457 cache::get_double_constructor_method()?,
458 tmp as c_double,
459 );
460 create_global_ref_from_local_ref(o, jni_env)
461 }
462}
463
464pub(crate) unsafe fn f64_from_jobject(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<f64> {
465 if obj.is_null() {
466 Err(errors::J4RsError::JniError(
467 "Attempt to create an f64 from null".to_string(),
468 ))
469 } else {
470 let v = (opt_to_res(cache::get_jni_call_double_method())?)(
471 jni_env,
472 obj,
473 cache::get_double_to_double_method()?,
474 );
475 Ok(v)
476 }
477}
478
479macro_rules! primitive_array_from_jobject {
480 ($fn_name:ident, $rust_type:ty, $get_array_element:path, $release_array_element:path) => {
481 pub(crate) unsafe fn $fn_name(obj: jobject, jni_env: *mut JNIEnv) -> errors::Result<Vec<$rust_type>> {
482 if obj.is_null() {
483 Err(errors::J4RsError::JniError(
484 format!("Attempt to create an {} array from null", stringify!($rust_type)),
485 ))
486 } else {
487 let length = (opt_to_res(cache::get_jni_get_array_length())?)(
489 jni_env,
490 obj
491 ) as usize;
492 let val_ptr = (opt_to_res($get_array_element())?)(
493 jni_env,
494 obj,
495 ptr::null_mut()
496 );
497 if val_ptr.is_null() { return Err(errors::J4RsError::JniError(format!("{} failed", stringify!($get_array_element)))) }
498 let total_bytes = length.checked_mul(mem::size_of::<$rust_type>()).expect("array bytes overflow");
499 let mut vec = Vec::<$rust_type>::with_capacity(length);
500 ptr::copy_nonoverlapping(val_ptr as *const u8, vec.as_mut_ptr() as *mut u8, total_bytes);
503 vec.set_len(length);
504 (opt_to_res($release_array_element())?)(
505 jni_env,
506 obj,
507 val_ptr,
508 jni_sys::JNI_ABORT,
509 );
510 Ok(vec)
511 }
512 }
513 };
514}
515
516primitive_array_from_jobject!(i8_array_from_jobject, i8, cache::get_jni_get_byte_array_elements, cache::get_jni_release_byte_array_elements);
517primitive_array_from_jobject!(i16_array_from_jobject, i16, cache::get_jni_get_short_array_elements, cache::get_jni_release_short_array_elements);
518primitive_array_from_jobject!(u16_array_from_jobject, u16, cache::get_jni_get_char_array_elements, cache::get_jni_release_char_array_elements);
519primitive_array_from_jobject!(i32_array_from_jobject, i32, cache::get_jni_get_int_array_elements, cache::get_jni_release_int_array_elements);
520primitive_array_from_jobject!(i64_array_from_jobject, i64, cache::get_jni_get_long_array_elements, cache::get_jni_release_long_array_elements);
521primitive_array_from_jobject!(f32_array_from_jobject, f32, cache::get_jni_get_float_array_elements, cache::get_jni_release_float_array_elements);
522primitive_array_from_jobject!(f64_array_from_jobject, f64, cache::get_jni_get_double_array_elements, cache::get_jni_release_double_array_elements);
523primitive_array_from_jobject!(boolean_array_from_jobject, bool, cache::get_jni_get_boolean_array_elements, cache::get_jni_release_boolean_array_elements);
524
525pub(crate) unsafe fn string_from_jobject(
526 obj: jobject,
527 jni_env: *mut JNIEnv,
528) -> errors::Result<String> {
529 if obj.is_null() {
530 Err(errors::J4RsError::JniError(
531 "Attempt to create a String from null".to_string(),
532 ))
533 } else {
534 let s = (opt_to_res(cache::get_jni_get_string_utf_chars())?)(jni_env, obj, ptr::null_mut())
535 as *mut c_char;
536 let rust_string = utils::to_rust_string(s)?;
537
538 Ok(rust_string)
539 }
540}
541
542pub unsafe fn jstring_to_rust_string(jvm: &Jvm, java_string: jstring) -> errors::Result<String> {
543 let s = (opt_to_res(cache::get_jni_get_string_utf_chars())?)(
544 jvm.jni_env,
545 java_string,
546 ptr::null_mut(),
547 ) as *mut c_char;
548 let rust_string = utils::to_rust_string(s)?;
549 (opt_to_res(cache::get_jni_release_string_utf_chars())?)(jvm.jni_env, java_string, s);
550 Jvm::do_return(jvm.jni_env, rust_string)
551}
552
553pub(crate) unsafe fn throw_exception(message: &str, jni_env: *mut JNIEnv) -> errors::Result<i32> {
554 let message_jstring = utils::to_c_string_struct(message);
555 let i = (opt_to_res(cache::get_jni_throw_new())?)(
556 jni_env,
557 cache::get_invocation_exception_class()?,
558 message_jstring.as_ptr(),
559 );
560 Ok(i)
561}