1use std::any::{Any, TypeId};
16use std::collections::HashMap;
17use std::convert::TryFrom;
18use std::env;
19use std::ops::Drop;
20use std::os::raw::c_void;
21use std::path::{Path, PathBuf};
22use std::ptr;
23use std::sync::mpsc::channel;
24use std::{fs, thread, time};
25use std::borrow::Borrow;
26
27use jni_sys::{
28 self, jint, jobject, jsize, jstring, JNIEnv, JavaVM, JavaVMInitArgs, JavaVMOption,
29 JNI_EDETACHED, JNI_EEXIST, JNI_EINVAL, JNI_ENOMEM, JNI_ERR, JNI_EVERSION, JNI_OK, JNI_TRUE,
30 JNI_VERSION_1_6,
31};
32use libc::c_char;
33use serde::de::DeserializeOwned;
34
35use instance::{ChainableInstance, Instance, InstanceReceiver};
36
37use crate::{errors, set_java_vm};
38use crate::errors::{opt_to_res, J4RsError};
39use crate::jni_utils;
40use crate::provisioning;
41use crate::provisioning::{get_maven_settings, JavaArtifact, LocalJarArtifact, MavenArtifact};
42use crate::utils;
43use crate::{api_tweaks as tweaks, cache, InvocationArg, MavenSettings};
44
45use self::tweaks::cache_classloader_of;
46
47use super::logger::{debug, error, info, warn};
48
49pub(crate) mod instance;
50pub(crate) mod invocation_arg;
51
52include!(concat!(env!("OUT_DIR"), "/j4rs_init.rs"));
54
55const CLASS_STRING: &str = "java.lang.String";
56const CLASS_BOOLEAN: &str = "java.lang.Boolean";
57const CLASS_BYTE: &str = "java.lang.Byte";
58const CLASS_CHARACTER: &str = "java.lang.Character";
59const CLASS_SHORT: &str = "java.lang.Short";
60const CLASS_INTEGER: &str = "java.lang.Integer";
61const CLASS_LONG: &str = "java.lang.Long";
62const CLASS_FLOAT: &str = "java.lang.Float";
63const CLASS_DOUBLE: &str = "java.lang.Double";
64const CLASS_LIST: &str = "java.util.List";
65pub(crate) const PRIMITIVE_BOOLEAN: &str = "boolean";
66pub(crate) const PRIMITIVE_BYTE: &str = "byte";
67pub(crate) const PRIMITIVE_SHORT: &str = "short";
68pub(crate) const PRIMITIVE_INT: &str = "int";
69pub(crate) const PRIMITIVE_LONG: &str = "long";
70pub(crate) const PRIMITIVE_FLOAT: &str = "float";
71pub(crate) const PRIMITIVE_DOUBLE: &str = "double";
72pub(crate) const PRIMITIVE_CHAR: &str = "char";
73
74pub(crate) const PRIMITIVE_BOOLEAN_ARRAY: &str = "[Z";
75pub(crate) const PRIMITIVE_BYTE_ARRAY: &str = "[B";
76pub(crate) const PRIMITIVE_SHORT_ARRAY: &str = "[S";
77pub(crate) const PRIMITIVE_INT_ARRAY: &str = "[I";
78pub(crate) const PRIMITIVE_LONG_ARRAY: &str = "[J";
79pub(crate) const PRIMITIVE_FLOAT_ARRAY: &str = "[F";
80pub(crate) const PRIMITIVE_DOUBLE_ARRAY: &str = "[D";
81pub(crate) const PRIMITIVE_CHAR_ARRAY: &str = "[C";
82
83pub(crate) const CLASS_NATIVE_CALLBACK_TO_RUST_CHANNEL_SUPPORT: &str =
84 "org.astonbitecode.j4rs.api.invocation.NativeCallbackToRustChannelSupport";
85pub(crate) const CLASS_J4RS_EVENT_HANDLER: &str =
86 "org.astonbitecode.j4rs.api.jfx.handlers.J4rsEventHandler";
87pub(crate) const CLASS_J4RS_FXML_LOADER: &str =
88 "org.astonbitecode.j4rs.api.jfx.J4rsFxmlLoader";
89pub const _JNI_VERSION_10: jint = 0x000a0000;
90
91pub type Callback = fn(Jvm, Instance) -> ();
92
93#[derive(Clone)]
95pub struct Jvm {
96 pub(crate) jni_env: *mut JNIEnv,
97 detach_thread_on_drop: bool,
98}
99
100impl Jvm {
101 pub fn new(jvm_options: &[String], lib_name_to_load: Option<String>) -> errors::Result<Jvm> {
103 Self::create_jvm(jvm_options, lib_name_to_load)
104 }
105
106 pub fn attach_thread() -> errors::Result<Jvm> {
108 Self::create_jvm(&[], None)
109 }
110
111 pub fn attach_thread_with_no_detach_on_drop() -> errors::Result<Jvm> {
117 let mut jvm = Jvm::attach_thread()?;
118 jvm.detach_thread_on_drop(false);
119 Ok(jvm)
120 }
121
122 pub fn detach_thread_on_drop(&mut self, detach: bool) {
128 self.detach_thread_on_drop = detach;
129 }
130
131 fn create_jvm(jvm_options: &[String], lib_name_to_load: Option<String>) -> errors::Result<Jvm> {
134 debug("Creating a Jvm");
135 let mut jvm: *mut JavaVM = ptr::null_mut();
136 let mut jni_environment: *mut JNIEnv = ptr::null_mut();
137
138 let _g = cache::MUTEX.lock()?;
140
141 let result = if let Some(env) = cache::get_thread_local_env_opt() {
142 debug("A JVM is already created for this thread. Retrieving it...");
143 jni_environment = env;
144
145 JNI_OK
146 } else {
147 let created_vm = Self::get_created_vm();
148
149 let res_int = if created_vm.is_some() {
150 debug("A JVM is already created by another thread. Retrieving it...");
151 jni_environment = created_vm.unwrap();
152
153 JNI_OK
154 } else {
155 info("No JVMs exist. Creating a new one...");
156 let mut cstrings_to_drop: Vec<*mut c_char> = Vec::with_capacity(jvm_options.len());
157 let mut jvm_options_vec: Vec<JavaVMOption> = jvm_options
158 .iter()
159 .map(|opt| {
160 let cstr = utils::to_c_string(opt);
161 let jo = JavaVMOption {
162 optionString: cstr,
163 extraInfo: ptr::null_mut() as *mut c_void,
164 };
165 cstrings_to_drop.push(cstr);
166 jo
167 })
168 .collect();
169
170 let mut jvm_arguments = JavaVMInitArgs {
171 version: JNI_VERSION_1_6,
172 nOptions: jvm_options.len() as i32,
173 options: jvm_options_vec.as_mut_ptr(),
174 ignoreUnrecognized: JNI_TRUE,
175 };
176
177 let int_result = tweaks::create_java_vm(
178 &mut jvm,
179 (&mut jni_environment as *mut *mut JNIEnv) as *mut *mut c_void,
180 (&mut jvm_arguments as *mut JavaVMInitArgs) as *mut c_void,
181 );
182
183 cstrings_to_drop
184 .into_iter()
185 .for_each(|s| unsafe {utils::drop_c_string(s)});
186
187 int_result
188 };
189
190 res_int
191 };
192
193 if result != JNI_OK {
194 let error_message = match result {
195 JNI_EDETACHED => "thread detached from the JVM",
196 JNI_EEXIST => "JVM already created",
197 JNI_EINVAL => "invalid arguments",
198 JNI_ENOMEM => "not enough memory",
199 JNI_ERR => "unknown error",
200 JNI_EVERSION => "JNI version error",
201 _ => "unknown JNI error value",
202 };
203
204 Err(J4RsError::JavaError(
205 format!("Could not create the JVM: {}", error_message).to_string(),
206 ))
207 } else {
208 let jvm = unsafe { Self::try_from(jni_environment)? };
209 if let Some(libname) = lib_name_to_load {
210 debug(&format!(
212 "Initializing NativeCallbackSupport with libname {}",
213 libname
214 ));
215 jvm.invoke_static(
216 CLASS_NATIVE_CALLBACK_TO_RUST_CHANNEL_SUPPORT,
217 "initialize",
218 &[InvocationArg::try_from(libname)?],
219 )?;
220 debug("NativeCallbackSupport initialized");
221 }
222
223 Ok(jvm)
224 }
225 }
226
227 pub unsafe fn try_from(jni_environment: *mut JNIEnv) -> errors::Result<Jvm> {
228 if cache::get_thread_local_env_opt().is_none() {
229 let _ = cache::get_jni_get_method_id().or_else(|| {
231 cache::set_jni_get_method_id(Some((**jni_environment).v1_6.GetMethodID))
232 });
233 let _ = cache::get_jni_get_static_method_id().or_else(|| {
234 cache::set_jni_get_static_method_id(Some(
235 (**jni_environment).v1_6.GetStaticMethodID,
236 ))
237 });
238 let _ = cache::get_jni_new_object()
239 .or_else(|| cache::set_jni_new_object(Some((**jni_environment).v1_6.NewObject)));
240 let _ = cache::get_jni_new_string_utf().or_else(|| {
241 cache::set_jni_new_string_utf(Some((**jni_environment).v1_6.NewStringUTF))
242 });
243 let _ = cache::get_jni_get_string_utf_chars().or_else(|| {
244 cache::set_jni_get_string_utf_chars(Some(
245 (**jni_environment).v1_6.GetStringUTFChars,
246 ))
247 });
248 let _ = cache::get_jni_release_string_utf_chars().or_else(|| {
249 cache::set_jni_release_string_utf_chars(Some(
250 (**jni_environment).v1_6.ReleaseStringUTFChars,
251 ))
252 });
253 let _ = cache::get_jni_call_object_method().or_else(|| {
254 cache::set_jni_call_object_method(Some((**jni_environment).v1_6.CallObjectMethod))
255 });
256 let _ = cache::get_jni_call_boolean_method().or_else(|| {
257 cache::set_jni_call_boolean_method(Some((**jni_environment).v1_6.CallBooleanMethod))
258 });
259 let _ = cache::get_jni_call_byte_method().or_else(|| {
260 cache::set_jni_call_byte_method(Some((**jni_environment).v1_6.CallByteMethod))
261 });
262 let _ = cache::get_jni_call_short_method().or_else(|| {
263 cache::set_jni_call_short_method(Some((**jni_environment).v1_6.CallShortMethod))
264 });
265 let _ = cache::get_jni_call_char_method().or_else(|| {
266 cache::set_jni_call_char_method(Some((**jni_environment).v1_6.CallCharMethod))
267 });
268 let _ = cache::get_jni_call_int_method().or_else(|| {
269 cache::set_jni_call_int_method(Some((**jni_environment).v1_6.CallIntMethod))
270 });
271 let _ = cache::get_jni_call_long_method().or_else(|| {
272 cache::set_jni_call_long_method(Some((**jni_environment).v1_6.CallLongMethod))
273 });
274 let _ = cache::get_jni_call_float_method().or_else(|| {
275 cache::set_jni_call_float_method(Some((**jni_environment).v1_6.CallFloatMethod))
276 });
277 let _ = cache::get_jni_call_double_method().or_else(|| {
278 cache::set_jni_call_double_method(Some((**jni_environment).v1_6.CallDoubleMethod))
279 });
280 let _ = cache::get_jni_call_void_method().or_else(|| {
281 cache::set_jni_call_void_method(Some((**jni_environment).v1_6.CallVoidMethod))
282 });
283 let _ = cache::get_jni_call_static_object_method().or_else(|| {
284 cache::set_jni_call_static_object_method(Some(
285 (**jni_environment).v1_6.CallStaticObjectMethod,
286 ))
287 });
288 let _ = cache::get_jni_get_array_length().or_else(|| {
289 cache::set_jni_get_array_length(Some(
290 (**jni_environment).v1_6.GetArrayLength,
291 ))
292 });
293 let _ = cache::get_jni_get_byte_array_elements().or_else(|| {
294 cache::set_jni_get_byte_array_elements(Some(
295 (**jni_environment).v1_6.GetByteArrayElements,
296 ))
297 });
298 let _ = cache::get_jni_release_byte_array_elements().or_else(|| {
299 cache::set_jni_release_byte_array_elements(Some(
300 (**jni_environment).v1_6.ReleaseByteArrayElements,
301 ))
302 });
303 let _ = cache::get_jni_get_short_array_elements().or_else(|| {
304 cache::set_jni_get_short_array_elements(Some(
305 (**jni_environment).v1_6.GetShortArrayElements,
306 ))
307 });
308 let _ = cache::get_jni_release_short_array_elements().or_else(|| {
309 cache::set_jni_release_short_array_elements(Some(
310 (**jni_environment).v1_6.ReleaseShortArrayElements,
311 ))
312 });
313 let _ = cache::get_jni_get_char_array_elements().or_else(|| {
314 cache::set_jni_get_char_array_elements(Some(
315 (**jni_environment).v1_6.GetCharArrayElements,
316 ))
317 });
318 let _ = cache::get_jni_release_char_array_elements().or_else(|| {
319 cache::set_jni_release_char_array_elements(Some(
320 (**jni_environment).v1_6.ReleaseCharArrayElements,
321 ))
322 });
323 let _ = cache::get_jni_get_int_array_elements().or_else(|| {
324 cache::set_jni_get_int_array_elements(Some(
325 (**jni_environment).v1_6.GetIntArrayElements,
326 ))
327 });
328 let _ = cache::get_jni_release_int_array_elements().or_else(|| {
329 cache::set_jni_release_int_array_elements(Some(
330 (**jni_environment).v1_6.ReleaseIntArrayElements,
331 ))
332 });
333 let _ = cache::get_jni_get_long_array_elements().or_else(|| {
334 cache::set_jni_get_long_array_elements(Some(
335 (**jni_environment).v1_6.GetLongArrayElements,
336 ))
337 });
338 let _ = cache::get_jni_release_long_array_elements().or_else(|| {
339 cache::set_jni_release_long_array_elements(Some(
340 (**jni_environment).v1_6.ReleaseLongArrayElements,
341 ))
342 });
343 let _ = cache::get_jni_get_float_array_elements().or_else(|| {
344 cache::set_jni_get_float_array_elements(Some(
345 (**jni_environment).v1_6.GetFloatArrayElements,
346 ))
347 });
348 let _ = cache::get_jni_release_float_array_elements().or_else(|| {
349 cache::set_jni_release_float_array_elements(Some(
350 (**jni_environment).v1_6.ReleaseFloatArrayElements,
351 ))
352 });
353 let _ = cache::get_jni_get_double_array_elements().or_else(|| {
354 cache::set_jni_get_double_array_elements(Some(
355 (**jni_environment).v1_6.GetDoubleArrayElements,
356 ))
357 });
358 let _ = cache::get_jni_release_double_array_elements().or_else(|| {
359 cache::set_jni_release_double_array_elements(Some(
360 (**jni_environment).v1_6.ReleaseDoubleArrayElements,
361 ))
362 });
363 let _ = cache::get_jni_get_boolean_array_elements().or_else(|| {
364 cache::set_jni_get_boolean_array_elements(Some(
365 (**jni_environment).v1_6.GetBooleanArrayElements,
366 ))
367 });
368 let _ = cache::get_jni_release_boolean_array_elements().or_else(|| {
369 cache::set_jni_release_boolean_array_elements(Some(
370 (**jni_environment).v1_6.ReleaseBooleanArrayElements,
371 ))
372 });
373 let _ = cache::get_jni_new_object_array().or_else(|| {
374 cache::set_jni_new_object_array(Some((**jni_environment).v1_6.NewObjectArray))
375 });
376 let _ = cache::get_jni_set_object_array_element().or_else(|| {
377 cache::set_jni_set_object_array_element(Some(
378 (**jni_environment).v1_6.SetObjectArrayElement,
379 ))
380 });
381 let ec = cache::get_jni_exception_check().or_else(|| {
382 cache::set_jni_exception_check(Some((**jni_environment).v1_6.ExceptionCheck))
383 });
384 let ed = cache::get_jni_exception_describe().or_else(|| {
385 cache::set_jni_exception_describe(Some((**jni_environment).v1_6.ExceptionDescribe))
386 });
387 let _ = cache::get_jni_exception_occured().or_else(|| {
388 cache::set_jni_exception_occured(Some((**jni_environment).v1_6.ExceptionOccurred))
389 });
390 let exclear = cache::get_jni_exception_clear().or_else(|| {
391 cache::set_jni_exception_clear(Some((**jni_environment).v1_6.ExceptionClear))
392 });
393 let _ = cache::get_jni_delete_local_ref().or_else(|| {
394 cache::set_jni_delete_local_ref(Some((**jni_environment).v1_6.DeleteLocalRef))
395 });
396 let _ = cache::get_jni_delete_global_ref().or_else(|| {
397 cache::set_jni_delete_global_ref(Some((**jni_environment).v1_6.DeleteGlobalRef))
398 });
399 let _ = cache::get_jni_new_global_ref().or_else(|| {
400 cache::set_jni_new_global_ref(Some((**jni_environment).v1_6.NewGlobalRef))
401 });
402 let _ = cache::get_jni_throw_new()
403 .or_else(|| cache::set_jni_throw_new(Some((**jni_environment).v1_6.ThrowNew)));
404 let _ = cache::get_is_same_object()
405 .or_else(|| cache::set_is_same_object(Some((**jni_environment).v1_6.IsSameObject)));
406
407 match (ec, ed, exclear) {
408 (Some(ec), Some(ed), Some(exclear)) => {
409 if (ec)(jni_environment) == JNI_TRUE {
410 (ed)(jni_environment);
411 (exclear)(jni_environment);
412 Err(J4RsError::JavaError(
413 "The VM cannot be started... Please check the logs.".to_string(),
414 ))
415 } else {
416 let jvm = Jvm {
417 jni_env: jni_environment,
418 detach_thread_on_drop: true,
419 };
420
421 cache::set_thread_local_env(Some(jni_environment));
422 cache::add_active_jvm();
423
424 Ok(jvm)
425 }
426 }
427 (_, _, _) => Err(J4RsError::JniError("Could not initialize the JVM: Error while trying to retrieve JNI functions.".to_string())),
428 }
429 } else {
430 let jvm = Jvm {
432 jni_env: jni_environment,
433 detach_thread_on_drop: true,
434 };
435
436 cache::set_thread_local_env(Some(jni_environment));
437 cache::add_active_jvm();
438
439 Ok(jvm)
440 }
441 }
442
443 pub fn create_instance(
445 &self,
446 class_name: &str,
447 inv_args: &[impl Borrow<InvocationArg>],
448 ) -> errors::Result<Instance> {
449 debug(&format!(
450 "Instantiating class {} using {} arguments",
451 class_name,
452 inv_args.len()
453 ));
454 unsafe {
455 let class_name_jstring: jstring =
457 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
458
459 let size = inv_args.len() as i32;
461 let array_ptr = {
462 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
463 self.jni_env,
464 size,
465 cache::get_invocation_arg_class()?,
466 ptr::null_mut(),
467 );
468 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
469 };
470 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
471
472 for i in 0..size {
474 let inv_arg_java =
476 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
477 (opt_to_res(cache::get_jni_set_object_array_element())?)(
479 self.jni_env,
480 array_ptr,
481 i,
482 inv_arg_java,
483 );
484 inv_arg_jobjects.push(inv_arg_java);
485 }
486 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
489 self.jni_env,
490 cache::get_factory_class()?,
491 cache::get_factory_instantiate_method()?,
492 class_name_jstring,
493 array_ptr,
494 );
495
496 Self::do_return(self.jni_env, ())?;
498
499 let java_instance_global_instance =
500 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
501 jni_utils::delete_java_ref(self.jni_env, array_ptr);
503 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
504 for inv_arg_jobject in inv_arg_jobjects {
505 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
506 }
507
508 Self::do_return(
510 self.jni_env,
511 Instance {
512 jinstance: java_instance_global_instance,
513 class_name: class_name.to_string(),
514 skip_deleting_jobject: false,
515 },
516 )
517 }
518 }
519
520 pub fn static_class(&self, class_name: &str) -> errors::Result<Instance> {
522 debug(&format!("Retrieving static class {}", class_name));
523 unsafe {
524 let class_name_jstring: jstring =
526 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
527
528 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
531 self.jni_env,
532 cache::get_factory_class()?,
533 cache::get_factory_create_for_static_method()?,
534 class_name_jstring,
535 );
536
537 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
538
539 Self::do_return(
541 self.jni_env,
542 Instance::from_jobject_with_global_ref(java_instance)?,
543 )
544 }
545 }
546
547 pub fn create_java_array(
551 &self,
552 class_name: &str,
553 inv_args: &[impl Borrow<InvocationArg>],
554 ) -> errors::Result<Instance> {
555 debug(&format!(
556 "Creating a java array of class {} with {} elements",
557 class_name,
558 inv_args.len()
559 ));
560 unsafe {
561 let class_name_jstring: jstring =
563 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
564
565 let size = inv_args.len() as i32;
567 let array_ptr = {
568 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
569 self.jni_env,
570 size,
571 cache::get_invocation_arg_class()?,
572 ptr::null_mut(),
573 );
574 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
575 };
576 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
577
578 for i in 0..size {
580 let inv_arg_java =
582 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
583 (opt_to_res(cache::get_jni_set_object_array_element())?)(
585 self.jni_env,
586 array_ptr,
587 i,
588 inv_arg_java,
589 );
590 inv_arg_jobjects.push(inv_arg_java);
591 }
592 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
595 self.jni_env,
596 cache::get_factory_class()?,
597 cache::get_factory_create_java_array_method()?,
598 class_name_jstring,
599 array_ptr,
600 );
601
602 Self::do_return(self.jni_env, ())?;
604
605 let java_instance_global_instance =
606 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
607 for inv_arg_jobject in inv_arg_jobjects {
609 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
610 }
611 jni_utils::delete_java_ref(self.jni_env, array_ptr);
612 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
613
614 Self::do_return(
616 self.jni_env,
617 Instance {
618 jinstance: java_instance_global_instance,
619 class_name: class_name.to_string(),
620 skip_deleting_jobject: false,
621 },
622 )
623 }
624 }
625
626 #[deprecated(since = "0.15.0", note = "Please use `java_list` instead")]
630 pub fn create_java_list(
631 &self,
632 class_name: &str,
633 inv_args: &[InvocationArg],
634 ) -> errors::Result<Instance> {
635 Jvm::do_create_java_list(self.jni_env, class_name, inv_args)
636 }
637
638 pub fn java_list<'a>(
640 &self,
641 inner_class_name: impl Into<&'a str>,
642 inv_args: Vec<impl TryInto<InvocationArg, Error=J4RsError>>,
643 ) -> errors::Result<Instance> {
644 let v: Result<Vec<InvocationArg>, J4RsError> =
645 inv_args.into_iter().map(|arg| arg.try_into()).collect();
646 Self::do_create_java_list(self.jni_env, inner_class_name.into(), v?.as_ref())
647 }
648
649 fn do_create_java_list(
650 jni_env: *mut JNIEnv,
651 class_name: &str,
652 inv_args: &[InvocationArg],
653 ) -> errors::Result<Instance> {
654 debug(&format!(
655 "Creating a java list of class {} with {} elements",
656 class_name,
657 inv_args.len()
658 ));
659 unsafe {
660 let class_name_jstring: jstring =
662 jni_utils::global_jobject_from_str(class_name, jni_env)?;
663
664 let size = inv_args.len() as i32;
666 let array_ptr = {
667 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
668 jni_env,
669 size,
670 cache::get_invocation_arg_class()?,
671 ptr::null_mut(),
672 );
673 jni_utils::create_global_ref_from_local_ref(j, jni_env)?
674 };
675 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
676
677 for i in 0..size {
679 let inv_arg_java = inv_args[i as usize].as_java_ptr_with_global_ref(jni_env)?;
681 (opt_to_res(cache::get_jni_set_object_array_element())?)(
683 jni_env,
684 array_ptr,
685 i,
686 inv_arg_java,
687 );
688 inv_arg_jobjects.push(inv_arg_java);
689 }
690 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
693 jni_env,
694 cache::get_factory_class()?,
695 cache::get_factory_create_java_list_method()?,
696 class_name_jstring,
697 array_ptr,
698 );
699
700 Self::do_return(jni_env, ())?;
702
703 let java_instance_global_instance =
704 jni_utils::create_global_ref_from_local_ref(java_instance, jni_env)?;
705 for inv_arg_jobject in inv_arg_jobjects {
707 jni_utils::delete_java_ref(jni_env, inv_arg_jobject);
708 }
709 jni_utils::delete_java_ref(jni_env, array_ptr);
710 jni_utils::delete_java_ref(jni_env, class_name_jstring);
711
712 Self::do_return(
714 jni_env,
715 Instance {
716 jinstance: java_instance_global_instance,
717 class_name: class_name.to_string(),
718 skip_deleting_jobject: false,
719 },
720 )
721 }
722 }
723
724 pub fn java_map<'a>(
726 &self,
727 key_class_name: impl Into<&'a str>,
728 value_class_name: impl Into<&'a str>,
729 inv_args: HashMap<
730 impl TryInto<InvocationArg, Error=J4RsError>,
731 impl TryInto<InvocationArg, Error=J4RsError>,
732 >,
733 ) -> errors::Result<Instance> {
734 let mut inv_args_results: Vec<Result<InvocationArg, J4RsError>> =
735 Vec::with_capacity(inv_args.len() * 2);
736 let mut i = 0;
737 let mut inv_args = inv_args;
738
739 for (key, val) in inv_args.drain() {
740 inv_args_results.insert(i, key.try_into());
741 i += 1;
742 inv_args_results.insert(i, val.try_into());
743 i += 1;
744 }
745 let inv_args: Result<Vec<InvocationArg>, J4RsError> = inv_args_results
746 .into_iter()
747 .map(|arg| arg.try_into())
748 .collect();
749 Self::do_create_java_map(
750 self.jni_env,
751 key_class_name.into(),
752 value_class_name.into(),
753 inv_args?.as_ref(),
754 )
755 }
756
757 fn do_create_java_map(
758 jni_env: *mut JNIEnv,
759 key_class_name: &str,
760 value_class_name: &str,
761 inv_args: &[InvocationArg],
762 ) -> errors::Result<Instance> {
763 debug(&format!(
764 "Creating a java map with keys of class {} and values of class {} with {} elements",
765 key_class_name,
766 value_class_name,
767 inv_args.len() / 2
768 ));
769 unsafe {
770 let key_class_name_jstring: jstring =
772 jni_utils::global_jobject_from_str(key_class_name, jni_env)?;
773 let value_class_name_jstring: jstring =
775 jni_utils::global_jobject_from_str(value_class_name, jni_env)?;
776
777 let size = inv_args.len() as i32;
779 let array_ptr = {
780 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
781 jni_env,
782 size,
783 cache::get_invocation_arg_class()?,
784 ptr::null_mut(),
785 );
786 jni_utils::create_global_ref_from_local_ref(j, jni_env)?
787 };
788 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
789
790 for i in 0..size {
792 let inv_arg_java = inv_args[i as usize].as_java_ptr_with_global_ref(jni_env)?;
794 (opt_to_res(cache::get_jni_set_object_array_element())?)(
796 jni_env,
797 array_ptr,
798 i,
799 inv_arg_java,
800 );
801 inv_arg_jobjects.push(inv_arg_java);
802 }
803 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
807 jni_env,
808 cache::get_factory_class()?,
809 cache::get_factory_create_java_map_method()?,
810 key_class_name_jstring,
811 value_class_name_jstring,
812 array_ptr,
813 );
814
815 Self::do_return(jni_env, ())?;
817
818 let java_instance_global_instance =
819 jni_utils::create_global_ref_from_local_ref(java_instance, jni_env)?;
820 for inv_arg_jobject in inv_arg_jobjects {
822 jni_utils::delete_java_ref(jni_env, inv_arg_jobject);
823 }
824 jni_utils::delete_java_ref(jni_env, array_ptr);
825 jni_utils::delete_java_ref(jni_env, value_class_name_jstring);
826 jni_utils::delete_java_ref(jni_env, key_class_name_jstring);
827
828 Self::do_return(
830 jni_env,
831 Instance {
832 jinstance: java_instance_global_instance,
833 class_name: "".to_string(),
834 skip_deleting_jobject: false,
835 },
836 )
837 }
838 }
839
840 pub fn invoke(
842 &self,
843 instance: &Instance,
844 method_name: &str,
845 inv_args: &[impl Borrow<InvocationArg>],
846 ) -> errors::Result<Instance> {
847 debug(&format!(
848 "Invoking method {} of class {} using {} arguments",
849 method_name,
850 instance.class_name,
851 inv_args.len()
852 ));
853 unsafe {
854 let method_name_jstring: jstring =
856 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
857
858 let size = inv_args.len() as i32;
860 let array_ptr = {
861 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
862 self.jni_env,
863 size,
864 cache::get_invocation_arg_class()?,
865 ptr::null_mut(),
866 );
867 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
868 };
869 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
870
871 for i in 0..size {
873 let inv_arg_java =
875 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
876 (opt_to_res(cache::get_jni_set_object_array_element())?)(
878 self.jni_env,
879 array_ptr,
880 i,
881 inv_arg_java,
882 );
883 inv_arg_jobjects.push(inv_arg_java);
884 }
885
886 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
888 self.jni_env,
889 instance.jinstance,
890 cache::get_invoke_method()?,
891 method_name_jstring,
892 array_ptr,
893 );
894
895 Self::do_return(self.jni_env, ())?;
897
898 let java_instance_global_instance =
899 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
900 for inv_arg_jobject in inv_arg_jobjects {
902 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
903 }
904 jni_utils::delete_java_ref(self.jni_env, array_ptr);
905 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
906
907 Self::do_return(
909 self.jni_env,
910 Instance {
911 jinstance: java_instance_global_instance,
912 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
913 skip_deleting_jobject: false,
914 },
915 )
916 }
917 }
918
919 pub fn field(&self, instance: &Instance, field_name: &str) -> errors::Result<Instance> {
921 debug(&format!(
922 "Retrieving field {} of class {}",
923 field_name, instance.class_name
924 ));
925 unsafe {
926 let field_name_jstring: jstring =
928 jni_utils::global_jobject_from_str(field_name, self.jni_env)?;
929
930 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
932 self.jni_env,
933 instance.jinstance,
934 cache::get_field_method()?,
935 field_name_jstring,
936 );
937
938 Self::do_return(self.jni_env, ())?;
940
941 let java_instance_global_instance =
942 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
943 jni_utils::delete_java_ref(self.jni_env, field_name_jstring);
945
946 Self::do_return(
948 self.jni_env,
949 Instance {
950 jinstance: java_instance_global_instance,
951 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
952 skip_deleting_jobject: false,
953 },
954 )
955 }
956 }
957
958 pub fn static_class_field(
960 &self,
961 class_name: &str,
962 field_name: &str,
963 ) -> errors::Result<Instance> {
964 debug(&format!(
965 "Retrieving field {} of static class {}",
966 field_name, class_name
967 ));
968 let i = self.static_class(class_name)?;
969 self.field(&i, field_name)
970 }
971
972 pub fn invoke_to_channel(
975 &self,
976 instance: &Instance,
977 method_name: &str,
978 inv_args: &[impl Borrow<InvocationArg>],
979 ) -> errors::Result<InstanceReceiver> {
980 debug(&format!("Invoking method {} of class {} using {} arguments. The result of the invocation will come via an InstanceReceiver", method_name, instance.class_name, inv_args.len()));
981 unsafe {
982 let (sender, rx) = channel();
984 let tx = Box::new(sender);
985 let raw_ptr = Box::into_raw(tx);
987 let address_string = format!("{:p}", raw_ptr);
989 let address = u64::from_str_radix(&address_string[2..], 16).unwrap();
990
991 let method_name_jstring: jstring =
993 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
994
995 let size = inv_args.len() as i32;
997 let array_ptr = {
998 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
999 self.jni_env,
1000 size,
1001 cache::get_invocation_arg_class()?,
1002 ptr::null_mut(),
1003 );
1004 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
1005 };
1006 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
1007
1008 for i in 0..size {
1010 let inv_arg_java =
1012 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
1013 (opt_to_res(cache::get_jni_set_object_array_element())?)(
1015 self.jni_env,
1016 array_ptr,
1017 i,
1018 inv_arg_java,
1019 );
1020 inv_arg_jobjects.push(inv_arg_java);
1021 }
1022
1023 (opt_to_res(cache::get_jni_call_void_method())?)(
1025 self.jni_env,
1026 instance.jinstance,
1027 cache::get_invoke_to_channel_method()?,
1028 address,
1029 method_name_jstring,
1030 array_ptr,
1031 );
1032
1033 Self::do_return(self.jni_env, ())?;
1035
1036 for inv_arg_jobject in inv_arg_jobjects {
1038 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
1039 }
1040 jni_utils::delete_java_ref(self.jni_env, array_ptr);
1041 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
1042
1043 Self::do_return(self.jni_env, InstanceReceiver::new(rx, address))
1045 }
1046 }
1047
1048 pub fn init_callback_channel(&self, instance: &Instance) -> errors::Result<InstanceReceiver> {
1052 debug("Initializing callback channel");
1053 unsafe {
1054 let (sender, rx) = channel();
1056 let tx = Box::new(sender);
1057 let raw_ptr = Box::into_raw(tx);
1059 let address_string = format!("{:p}", raw_ptr);
1061 let address = u64::from_str_radix(&address_string[2..], 16).unwrap();
1062
1063 (opt_to_res(cache::get_jni_call_void_method())?)(
1065 self.jni_env,
1066 instance.jinstance,
1067 cache::get_init_callback_channel_method()?,
1068 address,
1069 );
1070
1071 Self::do_return(self.jni_env, InstanceReceiver::new(rx, address))
1073 }
1074 }
1075
1076 pub fn invoke_static(
1078 &self,
1079 class_name: &str,
1080 method_name: &str,
1081 inv_args: &[impl Borrow<InvocationArg>],
1082 ) -> errors::Result<Instance> {
1083 debug(&format!(
1084 "Invoking static method {} of class {} using {} arguments",
1085 method_name,
1086 class_name,
1087 inv_args.len()
1088 ));
1089 unsafe {
1090 let class_name_jstring: jstring =
1092 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
1093 let tmp_java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1096 self.jni_env,
1097 cache::get_factory_class()?,
1098 cache::get_factory_create_for_static_method()?,
1099 class_name_jstring,
1100 );
1101
1102 let method_name_jstring: jstring =
1104 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
1105
1106 let size = inv_args.len() as i32;
1108 let array_ptr = {
1109 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
1110 self.jni_env,
1111 size,
1112 cache::get_invocation_arg_class()?,
1113 ptr::null_mut(),
1114 );
1115 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
1116 };
1117 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
1118 for i in 0..size {
1120 let inv_arg_java =
1122 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
1123 (opt_to_res(cache::get_jni_set_object_array_element())?)(
1125 self.jni_env,
1126 array_ptr,
1127 i,
1128 inv_arg_java,
1129 );
1130 inv_arg_jobjects.push(inv_arg_java);
1131 }
1132 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1134 self.jni_env,
1135 tmp_java_instance,
1136 cache::get_invoke_static_method()?,
1137 method_name_jstring,
1138 array_ptr,
1139 );
1140 jni_utils::delete_java_local_ref(self.jni_env, tmp_java_instance);
1142 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
1143 Self::do_return(self.jni_env, ())?;
1145
1146 for inv_arg_jobject in inv_arg_jobjects {
1148 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
1149 }
1150 jni_utils::delete_java_ref(self.jni_env, array_ptr);
1151 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
1152
1153 Self::do_return(
1155 self.jni_env,
1156 Instance::from_jobject_with_global_ref(java_instance)?,
1157 )
1158 }
1159 }
1160
1161 pub fn clone_instance(&self, instance: &Instance) -> errors::Result<Instance> {
1163 unsafe {
1164 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1166 self.jni_env,
1167 cache::get_class_to_invoke_clone_and_cast()?,
1168 cache::get_clone_static_method()?,
1169 instance.jinstance,
1170 );
1171
1172 Self::do_return(
1174 self.jni_env,
1175 Instance::from_jobject_with_global_ref(java_instance)?,
1176 )
1177 }
1178 }
1179
1180 pub fn cast(&self, from_instance: &Instance, to_class: &str) -> errors::Result<Instance> {
1182 debug(&format!("Casting to class {}", to_class));
1183 unsafe {
1184 let to_class_jstring: jstring =
1187 jni_utils::global_jobject_from_str(to_class, self.jni_env)?;
1188
1189 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1191 self.jni_env,
1192 cache::get_class_to_invoke_clone_and_cast()?,
1193 cache::get_cast_static_method()?,
1194 from_instance.jinstance,
1195 to_class_jstring,
1196 );
1197
1198 Self::do_return(self.jni_env, ())?;
1200
1201 jni_utils::delete_java_ref(self.jni_env, to_class_jstring);
1203
1204 Self::do_return(
1206 self.jni_env,
1207 Instance::from_jobject_with_global_ref(java_instance)?,
1208 )
1209 }
1210 }
1211
1212 pub fn check_equals(&self, instance: impl Borrow<Instance>, inv_arg: impl Borrow<InvocationArg>) -> errors::Result<bool> {
1217 debug(&format!("Checking equality between instances of {} and {}", instance.borrow().class_name(), inv_arg.borrow().class_name()));
1218 unsafe {
1219 let inv_arg_java_b = inv_arg.borrow().as_java_ptr_with_global_ref(self.jni_env)?;
1221 let java_boolean = (opt_to_res(cache::get_jni_call_boolean_method())?)(
1223 self.jni_env,
1224 instance.borrow().jinstance,
1225 cache::get_check_equals_method()?,
1226 inv_arg_java_b,
1227 );
1228
1229 Self::do_return(
1231 self.jni_env,
1232 java_boolean,
1233 )
1234 }
1235 }
1236
1237 pub fn instance_into_raw_object(&self, instance: Instance) -> errors::Result<jobject> {
1239 debug(&format!("Getting the raw jobject from instance of class {}", instance.borrow().class_name()));
1240 let object_instance = unsafe {
1242 (opt_to_res(cache::get_jni_call_object_method())?)(
1243 self.jni_env,
1244 instance.jinstance,
1245 cache::get_get_object_method()?,
1246 )};
1247
1248 Self::do_return(
1249 self.jni_env,
1250 object_instance,
1251 )
1252 }
1253
1254 pub fn into_raw(self) -> *mut JNIEnv {
1256 debug("Getting the raw JNIEnv from the Jvm");
1257
1258 self.jni_env
1259 }
1260
1261 pub fn to_rust_boxed<T>(&self, instance: Instance) -> errors::Result<Box<T>>
1263 where
1264 T: DeserializeOwned + Any,
1265 {
1266 macro_rules! rust_box_from_java_object {
1268 ($jni_transformation:path) => {{
1269 let object_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1271 self.jni_env,
1272 instance.jinstance,
1273 cache::get_get_object_method()?,
1274 );
1275 let object_instance =
1276 jni_utils::create_global_ref_from_local_ref(object_instance, self.jni_env)?;
1277 let v = Box::new($jni_transformation(object_instance, self.jni_env)?);
1278 let v_any = v as Box<dyn Any>;
1279
1280 jni_utils::delete_java_ref(self.jni_env, object_instance);
1281
1282 match v_any.downcast::<T>() {
1283 Ok(v) => Ok(v),
1284 Err(error) => Err(errors::J4RsError::RustError(format!(
1285 "Could not downcast to Rust type: {:?}",
1286 error
1287 ))),
1288 }
1289 }};
1290 }
1291
1292 let t_type = TypeId::of::<T>();
1293
1294
1295 unsafe {
1296 let object_class_name_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1298 self.jni_env,
1299 instance.jinstance,
1300 cache::get_get_object_class_name_method()?,
1301 );
1302 let object_class_name_instance = jni_utils::create_global_ref_from_local_ref(
1303 object_class_name_instance,
1304 self.jni_env,
1305 )?;
1306 let class_name = &(jni_utils::string_from_jobject(object_class_name_instance, self.jni_env)?);
1307 jni_utils::delete_java_ref(self.jni_env, object_class_name_instance);
1308 if t_type == TypeId::of::<String>() && JavaClass::String.get_class_str() == class_name {
1309 rust_box_from_java_object!(jni_utils::string_from_jobject)
1310 } else if t_type == TypeId::of::<i32>()
1311 && (JavaClass::Integer.get_class_str() == class_name || PRIMITIVE_INT == class_name)
1312 {
1313 rust_box_from_java_object!(jni_utils::i32_from_jobject)
1314 } else if t_type == TypeId::of::<i8>()
1315 && (JavaClass::Byte.get_class_str() == class_name || PRIMITIVE_BYTE == class_name)
1316 {
1317 rust_box_from_java_object!(jni_utils::i8_from_jobject)
1318 } else if t_type == TypeId::of::<i16>()
1319 && (JavaClass::Short.get_class_str() == class_name || PRIMITIVE_SHORT == class_name)
1320 {
1321 rust_box_from_java_object!(jni_utils::i16_from_jobject)
1322 } else if t_type == TypeId::of::<u16>()
1323 && (JavaClass::Character.get_class_str() == class_name || PRIMITIVE_CHAR == class_name)
1324 {
1325 rust_box_from_java_object!(jni_utils::u16_from_jobject)
1326 } else if t_type == TypeId::of::<i64>()
1327 && (JavaClass::Long.get_class_str() == class_name || PRIMITIVE_LONG == class_name)
1328 {
1329 rust_box_from_java_object!(jni_utils::i64_from_jobject)
1330 } else if t_type == TypeId::of::<f32>()
1331 && (JavaClass::Float.get_class_str() == class_name || PRIMITIVE_FLOAT == class_name)
1332 {
1333 rust_box_from_java_object!(jni_utils::f32_from_jobject)
1334 } else if t_type == TypeId::of::<f64>()
1335 && (JavaClass::Double.get_class_str() == class_name
1336 || PRIMITIVE_DOUBLE == class_name)
1337 {
1338 rust_box_from_java_object!(jni_utils::f64_from_jobject)
1339 } else if t_type == TypeId::of::<Vec<i8>>()
1340 && PRIMITIVE_BYTE_ARRAY == class_name
1341 {
1342 rust_box_from_java_object!(jni_utils::i8_array_from_jobject)
1343 } else if t_type == TypeId::of::<Vec<i16>>()
1344 && PRIMITIVE_SHORT_ARRAY == class_name
1345 {
1346 rust_box_from_java_object!(jni_utils::i16_array_from_jobject)
1347 } else if t_type == TypeId::of::<Vec<u16>>()
1348 && PRIMITIVE_CHAR_ARRAY == class_name
1349 {
1350 rust_box_from_java_object!(jni_utils::u16_array_from_jobject)
1351 } else if t_type == TypeId::of::<Vec<i32>>()
1352 && PRIMITIVE_INT_ARRAY == class_name
1353 {
1354 rust_box_from_java_object!(jni_utils::i32_array_from_jobject)
1355 } else if t_type == TypeId::of::<Vec<i64>>()
1356 && PRIMITIVE_LONG_ARRAY == class_name
1357 {
1358 rust_box_from_java_object!(jni_utils::i64_array_from_jobject)
1359 } else if t_type == TypeId::of::<Vec<f32>>()
1360 && PRIMITIVE_FLOAT_ARRAY == class_name
1361 {
1362 rust_box_from_java_object!(jni_utils::f32_array_from_jobject)
1363 } else if t_type == TypeId::of::<Vec<f64>>()
1364 && PRIMITIVE_DOUBLE_ARRAY == class_name
1365 {
1366 rust_box_from_java_object!(jni_utils::f64_array_from_jobject)
1367 } else if t_type == TypeId::of::<Vec<bool>>()
1368 && PRIMITIVE_BOOLEAN_ARRAY == class_name
1369 {
1370 rust_box_from_java_object!(jni_utils::boolean_array_from_jobject)
1371 } else {
1372 Ok(Box::new(self.to_rust_deserialized(instance)?))
1373 }
1374 }
1375 }
1376
1377 pub fn to_rust<T>(&self, instance: Instance) -> errors::Result<T>
1379 where
1380 T: DeserializeOwned + Any,
1381 {
1382 self.to_rust_boxed(instance).map(|v| *v)
1383 }
1384
1385 pub fn to_rust_deserialized<T>(&self, instance: Instance) -> errors::Result<T>
1386 where
1387 T: DeserializeOwned + Any,
1388 {
1389 unsafe {
1390 debug("Invoking the getJson method");
1391 let json_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1393 self.jni_env,
1394 instance.jinstance,
1395 cache::get_get_json_method()?,
1396 );
1397 let _ = Self::do_return(self.jni_env, "")?;
1398 debug("Transforming jstring to rust String");
1399 let global_json_instance =
1400 jni_utils::create_global_ref_from_local_ref(json_instance, self.jni_env)?;
1401 let json = jni_utils::jstring_to_rust_string(self, global_json_instance as jstring)?;
1402 jni_utils::delete_java_ref(self.jni_env, global_json_instance);
1403 Self::do_return(self.jni_env, serde_json::from_str(&json)?)
1404 }
1405 }
1406
1407 pub fn deploy_artifact<T: Any + JavaArtifact>(&self, artifact: &T) -> errors::Result<()> {
1413 let artifact = artifact as &dyn Any;
1414 if let Some(maven_artifact) = artifact.downcast_ref::<MavenArtifact>() {
1415 for repo in get_maven_settings().repos.into_iter() {
1416 let instance = self.create_instance(
1417 "org.astonbitecode.j4rs.api.deploy.SimpleMavenDeployer",
1418 &[InvocationArg::try_from(repo.uri)?,
1419 InvocationArg::try_from(&maven_artifact.base)?],
1420 )?;
1421
1422 let res = self.invoke(
1423 &instance,
1424 "deploy",
1425 &vec![
1426 InvocationArg::try_from(&maven_artifact.group)?,
1427 InvocationArg::try_from(&maven_artifact.id)?,
1428 InvocationArg::try_from(&maven_artifact.version)?,
1429 InvocationArg::try_from(&maven_artifact.qualifier)?,
1430 ],
1431 );
1432
1433 if res.is_ok() {
1434 break;
1435 }
1436 }
1437
1438 Ok(())
1439 } else if let Some(local_jar_artifact) = artifact.downcast_ref::<LocalJarArtifact>() {
1440 let instance = self.create_instance(
1441 "org.astonbitecode.j4rs.api.deploy.FileSystemDeployer",
1442 &[InvocationArg::try_from(&local_jar_artifact.base)?],
1443 )?;
1444
1445 let _ = self.invoke(
1446 &instance,
1447 "deploy",
1448 &[InvocationArg::try_from(&local_jar_artifact.path)?],
1449 )?;
1450 Ok(())
1451 } else {
1452 Err(J4RsError::GeneralError(format!(
1453 "Don't know how to deploy artifacts of {:?}",
1454 artifact.type_id()
1455 )))
1456 }
1457 }
1458
1459 pub fn copy_j4rs_libs_under(path: &str) -> errors::Result<()> {
1465 let mut pb = PathBuf::from(path);
1466 pb.push("deps");
1467 fs::create_dir_all(&pb)?;
1468
1469 let default_jassets_path_buf = utils::default_jassets_path()?;
1470 let default_jassets_path_string = default_jassets_path_buf.to_str().unwrap().to_owned();
1471
1472 let options = &mut fs_extra::dir::CopyOptions::new();
1474 options.overwrite = true;
1475 let _ = fs_extra::copy_items(vec![default_jassets_path_string].as_ref(), path, options)?;
1476
1477 let dynlibs: Vec<String> = {
1479 let mut dynlibs = vec![];
1480 for _i in 0..10 {
1483 dynlibs = utils::find_j4rs_dynamic_libraries_paths()?;
1484 if dynlibs.is_empty() {
1485 thread::sleep(time::Duration::from_millis(1000));
1486 } else {
1487 break;
1488 }
1489 }
1490 dynlibs
1491 };
1492 if dynlibs.is_empty() {
1493 let message = format!(
1494 "No j4rs dynamic libraries found for target triple {}. \
1495 The host triple during build is {}.",
1496 env::var("TARGET").unwrap_or("".to_string()),
1497 env::var("HOST").unwrap_or("UNKNOWN".to_string())
1498 );
1499 println!("cargo:warning={}", message);
1500 }
1501
1502 let _ = fs_extra::copy_items(&dynlibs, &pb, options)?;
1503
1504 Ok(())
1505 }
1506
1507 pub fn chain(&self, instance: &Instance) -> errors::Result<ChainableInstance<'_>> {
1509 ChainableInstance::new_with_instance_ref(instance, self)
1510 }
1511
1512 pub fn into_chain(&self, instance: Instance) -> ChainableInstance<'_> {
1514 ChainableInstance::new(instance, self)
1515 }
1516
1517 pub fn throw_invocation_exception(&self, message: &str) -> errors::Result<()> {
1519 unsafe {
1520 let _ = jni_utils::throw_exception(message, self.jni_env)?;
1521 }
1522 Ok(())
1523 }
1524
1525 pub(crate) fn do_return<T>(jni_env: *mut JNIEnv, to_return: T) -> errors::Result<T> {
1526 unsafe {
1527 if (opt_to_res(cache::get_jni_exception_check())?)(jni_env) == JNI_TRUE {
1528 let throwable = (opt_to_res(cache::get_jni_exception_occured())?)(jni_env);
1529 let throwable_string = Self::get_throwable_string(throwable, jni_env)?;
1530 (opt_to_res(cache::get_jni_exception_clear())?)(jni_env);
1531 Err(J4RsError::JavaError(throwable_string))
1532 } else {
1533 Ok(to_return)
1534 }
1535 }
1536 }
1537
1538 unsafe fn get_throwable_string(throwable: jobject, jni_env: *mut JNIEnv) -> errors::Result<String> {
1539 let java_string = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1540 jni_env,
1541 cache::get_utils_class()?,
1542 cache::get_utils_exception_to_string_method()?,
1543 throwable,
1544 );
1545 let to_ret = jni_utils::string_from_jobject(java_string, jni_env);
1546 jni_utils::delete_java_local_ref(jni_env, java_string);
1547 to_ret
1548 }
1549
1550 fn get_created_vm() -> Option<*mut JNIEnv> {
1552 unsafe {
1553 let mut created_vms_size: jsize = 0;
1555 tweaks::get_created_java_vms(
1556 &mut Vec::with_capacity(created_vms_size as usize),
1557 0,
1558 &mut created_vms_size,
1559 );
1560
1561 if created_vms_size == 0 {
1562 None
1563 } else {
1564 debug(&format!(
1565 "Retrieving the first of {} created JVMs",
1566 created_vms_size
1567 ));
1568 let mut buffer: Vec<*mut JavaVM> = Vec::with_capacity(2);
1570 for _ in 0..created_vms_size {
1571 buffer.push(ptr::null_mut());
1572 }
1573
1574 let retjint = tweaks::get_created_java_vms(
1575 &mut buffer,
1576 created_vms_size,
1577 &mut created_vms_size,
1578 );
1579 if retjint == JNI_OK {
1580 let act = (**buffer[0]).v1_4.AttachCurrentThread;
1581 let mut jni_environment: *mut JNIEnv = ptr::null_mut();
1582 (act)(
1583 buffer[0],
1584 (&mut jni_environment as *mut *mut JNIEnv) as *mut *mut c_void,
1585 ptr::null_mut(),
1586 );
1587 Some(jni_environment)
1588 } else {
1589 error(&format!(
1590 "Error while retrieving the created JVMs: {}",
1591 retjint
1592 ));
1593 None
1594 }
1595 }
1596 }
1597 }
1598
1599 fn detach_current_thread(&self) {
1600 unsafe {
1601 let mut created_vms_size: jsize = 0;
1603 tweaks::get_created_java_vms(
1604 &mut Vec::with_capacity(created_vms_size as usize),
1605 0,
1606 &mut created_vms_size,
1607 );
1608
1609 if created_vms_size > 0 {
1610 let mut buffer: Vec<*mut JavaVM> = Vec::with_capacity(created_vms_size as usize);
1612 for _ in 0..created_vms_size {
1613 buffer.push(ptr::null_mut());
1614 }
1615
1616 let retjint = tweaks::get_created_java_vms(
1617 &mut buffer,
1618 created_vms_size,
1619 &mut created_vms_size,
1620 );
1621 if retjint == JNI_OK {
1622 let dct = (**buffer[0]).v1_4.DetachCurrentThread;
1623 (dct)(buffer[0]);
1624 } else {
1625 warn(&format!(
1626 "Error while retrieving the created JVMs: {}",
1627 retjint
1628 ));
1629 }
1630 }
1631 }
1632 }
1633
1634 pub fn select(instance_receivers: &[&InstanceReceiver]) -> errors::Result<(usize, Instance)> {
1639 loop {
1640 for (index, ir) in instance_receivers.iter().enumerate() {
1641 let res = ir.rx.try_recv();
1642 if res.is_ok() {
1643 return Ok((index, res.unwrap()));
1644 }
1645 }
1646 thread::yield_now();
1647 }
1648 }
1649
1650 pub fn select_timeout(
1657 instance_receivers: &[&InstanceReceiver],
1658 timeout: &time::Duration,
1659 ) -> errors::Result<(usize, Instance)> {
1660 let start = time::Instant::now();
1661 loop {
1662 for (index, ir) in instance_receivers.iter().enumerate() {
1663 let res = ir.rx.try_recv();
1664 if res.is_ok() {
1665 return Ok((index, res.unwrap()));
1666 }
1667 }
1668 if &start.elapsed() > timeout {
1669 return Err(J4RsError::Timeout);
1670 }
1671 thread::yield_now();
1672 }
1673 }
1674}
1675
1676impl Drop for Jvm {
1677 fn drop(&mut self) {
1678 if cache::remove_active_jvm() <= 0 {
1679 if self.detach_thread_on_drop {
1680 self.detach_current_thread();
1681 }
1682 cache::set_thread_local_env(None);
1683 }
1684 }
1685}
1686
1687pub struct JvmBuilder<'a> {
1689 classpath_entries: Vec<ClasspathEntry<'a>>,
1690 java_opts: Vec<JavaOpt<'a>>,
1691 no_implicit_classpath: bool,
1692 detach_thread_on_drop: bool,
1693 lib_name_opt: Option<String>,
1694 skip_setting_native_lib: bool,
1695 base_path: Option<String>,
1696 maven_settings: MavenSettings,
1697 javafx: bool,
1698 default_classloader: bool,
1699 java_vm_opt: Option<*mut JavaVM>,
1700 jobject_within_valid_classloader_opt: Option<jobject>,
1701}
1702
1703impl<'a> JvmBuilder<'a> {
1704 pub fn new<'b>() -> JvmBuilder<'b> {
1706 JvmBuilder {
1707 classpath_entries: Vec::new(),
1708 java_opts: Vec::new(),
1709 no_implicit_classpath: false,
1710 detach_thread_on_drop: true,
1711 lib_name_opt: None,
1712 skip_setting_native_lib: false,
1713 base_path: None,
1714 maven_settings: MavenSettings::default(),
1715 javafx: false,
1716 default_classloader: false,
1717 java_vm_opt: None,
1718 jobject_within_valid_classloader_opt: None
1719 }
1720 }
1721
1722 pub fn classpath_entry(&'a mut self, cp_entry: ClasspathEntry<'a>) -> &'a mut JvmBuilder<'a> {
1724 self.classpath_entries.push(cp_entry);
1725 self
1726 }
1727
1728 pub fn classpath_entries(
1730 &'a mut self,
1731 cp_entries: Vec<ClasspathEntry<'a>>,
1732 ) -> &'a mut JvmBuilder<'a> {
1733 for cp_entry in cp_entries {
1734 self.classpath_entries.push(cp_entry);
1735 }
1736 self
1737 }
1738
1739 pub fn java_opt(&'a mut self, opt: JavaOpt<'a>) -> &'a mut JvmBuilder<'a> {
1741 self.java_opts.push(opt);
1742 self
1743 }
1744
1745 pub fn java_opts(&'a mut self, opts: Vec<JavaOpt<'a>>) -> &'a mut JvmBuilder<'a> {
1747 for opt in opts {
1748 self.java_opts.push(opt);
1749 }
1750 self
1751 }
1752
1753 pub fn with_no_implicit_classpath(&'a mut self) -> &'a mut JvmBuilder<'a> {
1756 self.no_implicit_classpath = true;
1757 self
1758 }
1759
1760 pub fn detach_thread_on_drop(&'a mut self, detach_thread_on_drop: bool) -> &'a mut JvmBuilder<'a> {
1766 self.detach_thread_on_drop = detach_thread_on_drop;
1767 self
1768 }
1769
1770 pub fn with_native_lib_name(&'a mut self, lib_name: &str) -> &'a mut JvmBuilder<'a> {
1775 self.lib_name_opt = Some(lib_name.to_string());
1776 self
1777 }
1778
1779 pub fn skip_setting_native_lib(&'a mut self) -> &'a mut JvmBuilder<'a> {
1782 self.skip_setting_native_lib = true;
1783 self
1784 }
1785
1786 pub fn with_base_path(&'a mut self, base_path: &str) -> &'a mut JvmBuilder<'a> {
1789 self.base_path = Some(base_path.to_string());
1790 self
1791 }
1792
1793 pub fn with_maven_settings(&'a mut self, maven_settings: MavenSettings) -> &'a mut JvmBuilder<'a> {
1795 self.maven_settings = maven_settings;
1796 self
1797 }
1798
1799 pub fn with_javafx_support(&'a mut self) -> &'a mut JvmBuilder<'a> {
1801 self.javafx = true;
1802 self
1803 }
1804
1805 pub fn with_java_vm(&'a mut self, java_vm: *mut JavaVM) -> &'a mut JvmBuilder<'a> {
1809 self.java_vm_opt = Some(java_vm);
1810 self
1811 }
1812
1813 pub fn with_classloader_of_activity(&'a mut self, jobject_within_valid_classloader: jobject) -> &'a mut JvmBuilder<'a> {
1831 self.jobject_within_valid_classloader_opt = Some(jobject_within_valid_classloader);
1832 let tmp = self.detach_thread_on_drop(false);
1837 let tmp = tmp.with_no_implicit_classpath();
1838 tmp
1839 }
1840
1841 pub fn with_default_classloader(&'a mut self) -> &'a mut JvmBuilder<'a> {
1865 self.default_classloader = true;
1866 self
1867 }
1868
1869 pub fn build(&mut self) -> errors::Result<Jvm> {
1871 if !self.default_classloader {
1872 self.java_opts.push(JavaOpt::new(
1874 "-Djava.system.class.loader=org.astonbitecode.j4rs.api.deploy.J4rsClassLoader",
1875 ));
1876 self.java_opts.push(JavaOpt::new("-Xshare:off"));
1877 self.java_opts.push(JavaOpt::new(
1878 "-Djdk.net.URLClassPath.showIgnoredClassPathEntries=true",
1879 ));
1880 }
1881
1882 let classpath = if self.no_implicit_classpath {
1883 self.classpath_entries
1884 .iter()
1885 .fold(".".to_string(), |all, elem| {
1886 format!("{}{}{}", all, utils::classpath_sep(), elem.to_string())
1887 })
1888 } else {
1889 let jassets_path = self.get_jassets_path()?;
1891 let j4rs_jar_to_use = format!("j4rs-{}-jar-with-dependencies.jar", j4rs_version());
1893 let j4rs_testing_jar_to_use = format!("j4rs-testing-{}.jar", j4rs_version());
1894 let j4rs_javafx_jar_to_use = format!("j4rs-javafx-{}.jar", j4rs_version());
1895 let mut cp_string = String::new();
1897 for entry in std::fs::read_dir(jassets_path)? {
1898 let path = entry?.path();
1899 if let Some(file_name) = opt_to_res(path.file_name())?.to_str() {
1900 if !file_name.contains("j4rs-") || file_name.ends_with(&j4rs_jar_to_use) || file_name.ends_with(&j4rs_testing_jar_to_use) || file_name.ends_with(&j4rs_javafx_jar_to_use) {
1901 if !cp_string.is_empty() {
1902 cp_string.push_str(utils::classpath_sep());
1903 }
1904 if let Some(path) = path.to_str() {
1905 cp_string.push_str(path);
1906 }
1907 }
1908 }
1909 }
1910
1911 let default_class_path = format!("-Djava.class.path={}", cp_string);
1912
1913 self.classpath_entries
1914 .iter()
1915 .fold(default_class_path, |all, elem| {
1916 format!("{}{}{}", all, utils::classpath_sep(), elem.to_string())
1917 })
1918 };
1919 info(&format!("Setting classpath to {}", classpath));
1920
1921 let mut jvm_options = if self.no_implicit_classpath {
1923 vec![classpath]
1924 } else {
1925 let default_library_path = utils::java_library_path()?;
1926 info(&format!("Setting library path to {}", default_library_path));
1927 vec![classpath, default_library_path]
1928 };
1929
1930 if self.javafx {
1931 let jassets_path = self.get_jassets_path()?;
1932 let jassets_path_string = jassets_path.to_str().unwrap_or(".");
1933 let modules_path = format!("--module-path {}", jassets_path_string);
1934 jvm_options.push(modules_path);
1935 jvm_options.push(
1936 "--add-modules javafx.base,javafx.controls,javafx.graphics,javafx.fxml".to_string(),
1937 );
1938 }
1939 self.java_opts
1940 .clone()
1941 .into_iter()
1942 .for_each(|opt| jvm_options.push(opt.to_string()));
1943
1944 let lib_name_opt = if self.lib_name_opt.is_none() && !self.skip_setting_native_lib && cfg!(not(target_os = "android")) {
1946 let deps_dir = utils::deps_dir()?;
1947 let found_libs: Vec<String> = if Path::new(&deps_dir).exists() {
1948 utils::find_j4rs_dynamic_libraries_names()?
1949 } else {
1950 let default_lib_name = if cfg!(windows) {
1953 "l4rs.dll".to_string()
1954 } else {
1955 "libj4rs.so".to_string()
1956 };
1957 info(&format!(
1958 "Deps directory not found. Setting the library name to search to default: {}",
1959 default_lib_name
1960 ));
1961 vec![default_lib_name]
1962 };
1963
1964 let lib_name_opt = if !found_libs.is_empty() {
1965 let a_lib = found_libs[0].clone().replace("lib", "");
1966
1967 let dot_splitted: Vec<&str> = a_lib.split('.').collect();
1968 let name = dot_splitted[0].to_string();
1969 info(&format!(
1970 "Passing to the Java world the name of the library to load: {}",
1971 name
1972 ));
1973 Some(name)
1974 } else {
1975 None
1976 };
1977 lib_name_opt
1978 } else if self.lib_name_opt.is_some() && !self.skip_setting_native_lib {
1979 let name = self.lib_name_opt.clone();
1980 info(&format!(
1981 "Passing to the Java world the name of the library to load: {}",
1982 name.as_ref().unwrap()
1983 ));
1984 name
1985 } else {
1986 None
1987 };
1988
1989 provisioning::set_maven_settings(&self.maven_settings);
1990
1991 let jvm_res = if self.java_vm_opt.is_some() {
1992 set_java_vm(self.java_vm_opt.unwrap());
1994 Jvm::attach_thread()
1995 } else {
1996 Jvm::new(&jvm_options, lib_name_opt)
1997 };
1998
1999 jvm_res.and_then(|mut jvm| {
2000 if !self.detach_thread_on_drop {
2001 jvm.detach_thread_on_drop(false);
2002 }
2003 if self.jobject_within_valid_classloader_opt.is_some() {
2004 cache_classloader_of(jvm.jni_env, self.jobject_within_valid_classloader_opt.unwrap())?;
2005 }
2006 Ok(jvm)
2007 })
2008 }
2009
2010 pub fn already_initialized() -> errors::Result<Jvm> {
2014 Jvm::new(&[], None)
2015 }
2016
2017 fn get_jassets_path(&self) -> errors::Result<PathBuf> {
2018 match &self.base_path {
2019 Some(base_path_string) => {
2020 let mut pb = PathBuf::from(base_path_string);
2021 pb.push("jassets");
2022 let mut global_jassets_path_opt = cache::JASSETS_PATH.lock()?;
2023 *global_jassets_path_opt = Some(pb.clone());
2024 Ok(pb)
2025 }
2026 None => utils::default_jassets_path(),
2027 }
2028 }
2029}
2030
2031pub enum JavaClass<'a> {
2033 Void,
2034 String,
2035 Boolean,
2036 Byte,
2037 Character,
2038 Short,
2039 Integer,
2040 Long,
2041 Float,
2042 Double,
2043 List,
2044 Of(&'a str),
2045}
2046
2047impl<'a> JavaClass<'a> {
2048 pub fn get_class_str(&self) -> &'a str {
2049 match self {
2050 Self::Void => "void",
2051 Self::String => CLASS_STRING,
2052 Self::Boolean => CLASS_BOOLEAN,
2053 Self::Byte => CLASS_BYTE,
2054 Self::Character => CLASS_CHARACTER,
2055 Self::Short => CLASS_SHORT,
2056 Self::Integer => CLASS_INTEGER,
2057 Self::Long => CLASS_LONG,
2058 Self::Float => CLASS_FLOAT,
2059 Self::Double => CLASS_DOUBLE,
2060 Self::List => CLASS_LIST,
2061 Self::Of(str) => str,
2062 }
2063 }
2064}
2065
2066impl<'a> From<JavaClass<'a>> for &'a str {
2067 fn from(java_class: JavaClass<'a>) -> &'a str {
2068 java_class.get_class_str()
2069 }
2070}
2071
2072impl<'a> From<&'a str> for JavaClass<'a> {
2073 fn from(java_class: &'a str) -> JavaClass<'a> {
2074 match java_class {
2075 "void" => Self::Void,
2076 CLASS_STRING => Self::String,
2077 CLASS_BOOLEAN => Self::Boolean,
2078 CLASS_BYTE => Self::Byte,
2079 CLASS_CHARACTER => Self::Character,
2080 CLASS_SHORT => Self::Short,
2081 CLASS_INTEGER => Self::Integer,
2082 CLASS_LONG => Self::Long,
2083 CLASS_FLOAT => Self::Float,
2084 CLASS_DOUBLE => Self::Double,
2085 CLASS_LIST => Self::List,
2086 str => Self::Of(str),
2087 }
2088 }
2089}
2090
2091pub enum Null<'a> {
2096 String,
2097 Boolean,
2098 Byte,
2099 Character,
2100 Short,
2101 Integer,
2102 Long,
2103 Float,
2104 Double,
2105 List,
2106 Of(&'a str),
2107}
2108
2109#[derive(Debug, Clone)]
2111pub struct ClasspathEntry<'a>(&'a str);
2112
2113impl<'a> ClasspathEntry<'a> {
2114 pub fn new(classpath_entry: &str) -> ClasspathEntry<'_> {
2115 ClasspathEntry(classpath_entry)
2116 }
2117}
2118
2119impl<'a> ToString for ClasspathEntry<'a> {
2120 fn to_string(&self) -> String {
2121 self.0.to_string()
2122 }
2123}
2124
2125#[derive(Debug, Clone)]
2127pub struct JavaOpt<'a>(&'a str);
2128
2129impl<'a> JavaOpt<'a> {
2130 pub fn new(java_opt: &str) -> JavaOpt<'_> {
2131 JavaOpt(java_opt)
2132 }
2133}
2134
2135impl<'a> ToString for JavaOpt<'a> {
2136 fn to_string(&self) -> String {
2137 self.0.to_string()
2138 }
2139}
2140
2141#[cfg(test)]
2142mod api_unit_tests {
2143 use crate::lib_unit_tests::create_tests_jvm;
2144 use super::*;
2145
2146 #[test]
2147 fn jvm_builder() -> errors::Result<()> {
2148 let res = create_tests_jvm();
2149 assert!(res.is_ok());
2150 let one_more_res = JvmBuilder::already_initialized();
2151 assert!(one_more_res.is_ok());
2152
2153 Ok(())
2154 }
2155
2156 #[test]
2157 fn test_copy_j4rs_libs_under() -> errors::Result<()> {
2158 let newdir = "./newdir";
2159 Jvm::copy_j4rs_libs_under(newdir)?;
2160
2161 let _ = std::fs::remove_dir_all(newdir);
2162
2163 Ok(())
2164 }
2165
2166 #[test]
2167 fn test_select() -> errors::Result<()> {
2168 let (tx1, rx1) = channel();
2169 let ir1 = InstanceReceiver::new(rx1, 0);
2170 let (_tx2, rx2) = channel();
2171 let ir2 = InstanceReceiver::new(rx2, 0);
2172 let (tx3, rx3) = channel();
2173 let ir3 = InstanceReceiver::new(rx3, 0);
2174
2175 thread::spawn(move || {
2176 let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2177 thread::sleep(time::Duration::from_millis(10));
2179 let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2180 thread::sleep(time::Duration::from_millis(10));
2181 let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2182 });
2183
2184 let (index1, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2185 let (index2, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2186 let (index3, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2187 assert_eq!(index1, 2);
2188 assert_eq!(index2, 0);
2189 assert_eq!(index3, 2);
2190
2191 Ok(())
2192 }
2193
2194 #[test]
2195 fn test_select_timeout() -> errors::Result<()> {
2196 let (tx1, rx1) = channel();
2197 let ir1 = InstanceReceiver::new(rx1, 0);
2198 let (tx2, rx2) = channel();
2199 let ir2 = InstanceReceiver::new(rx2, 0);
2200
2201 thread::spawn(move || {
2202 let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2203 thread::sleep(time::Duration::from_millis(10));
2205 let _ = tx2.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2206 });
2207
2208 let d = time::Duration::from_millis(500);
2209 let (index1, _) = Jvm::select_timeout(&[&ir1, &ir2], &d)?;
2210 let (index2, _) = Jvm::select_timeout(&[&ir1, &ir2], &d)?;
2211 assert!(Jvm::select_timeout(&[&ir1, &ir2], &d).is_err());
2212 assert_eq!(index1, 0);
2213 assert_eq!(index2, 1);
2214
2215 Ok(())
2216 }
2217
2218 #[test]
2219 fn test_java_class_creation() -> errors::Result<()> {
2220 assert_eq!(JavaClass::Void.get_class_str(), "void");
2221 assert_eq!(JavaClass::String.get_class_str(), CLASS_STRING);
2222 assert_eq!(JavaClass::Boolean.get_class_str(), CLASS_BOOLEAN);
2223 assert_eq!(JavaClass::Byte.get_class_str(), CLASS_BYTE);
2224 assert_eq!(JavaClass::Character.get_class_str(), CLASS_CHARACTER);
2225 assert_eq!(JavaClass::Short.get_class_str(), CLASS_SHORT);
2226 assert_eq!(JavaClass::Integer.get_class_str(), CLASS_INTEGER);
2227 assert_eq!(JavaClass::Long.get_class_str(), CLASS_LONG);
2228 assert_eq!(JavaClass::Float.get_class_str(), CLASS_FLOAT);
2229 assert_eq!(JavaClass::Double.get_class_str(), CLASS_DOUBLE);
2230 assert_eq!(JavaClass::List.get_class_str(), CLASS_LIST);
2231 assert_eq!(
2232 JavaClass::Of("a.java.Class").get_class_str(),
2233 "a.java.Class"
2234 );
2235
2236 Ok(())
2237 }
2238
2239 #[test]
2240 fn test_byte_array_to_rust() -> errors::Result<()> {
2241 let jvm = create_tests_jvm()?;
2242 let rust_value: Vec<i8> = vec![-3_i8, 7_i8, 8_i8];
2243 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2244 let java_instance = jvm.create_java_array(PRIMITIVE_BYTE, &ia)?;
2245 let rust_value_from_java: Vec<i8> = jvm.to_rust(java_instance)?;
2246 assert_eq!(rust_value_from_java, rust_value);
2247
2248 Ok(())
2249 }
2250
2251 #[test]
2252 fn test_short_array_to_rust() -> errors::Result<()> {
2253 let jvm = create_tests_jvm()?;
2254 let rust_value: Vec<i16> = vec![-3_i16, 7_i16, 10000_i16];
2255 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2256 let java_instance = jvm.create_java_array(PRIMITIVE_SHORT, &ia)?;
2257 let rust_value_from_java: Vec<i16> = jvm.to_rust(java_instance)?;
2258 assert_eq!(rust_value_from_java, rust_value);
2259
2260 Ok(())
2261 }
2262
2263 #[test]
2264 fn test_char_array_to_rust() -> errors::Result<()> {
2265 let jvm = create_tests_jvm()?;
2266 let rust_value: Vec<u16> = vec![3_u16, 7_u16, 10000_u16];
2267 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2268 let java_instance = jvm.create_java_array(PRIMITIVE_CHAR, &ia)?;
2269 let rust_value_from_java: Vec<u16> = jvm.to_rust(java_instance)?;
2270 assert_eq!(rust_value_from_java, rust_value);
2271
2272 Ok(())
2273 }
2274
2275 #[test]
2276 fn test_int_array_to_rust() -> errors::Result<()> {
2277 let jvm = create_tests_jvm()?;
2278 let rust_value: Vec<i32> = vec![-100_000, -1_000_000, 1_000_000];
2279 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2280 let java_instance = jvm.create_java_array(PRIMITIVE_INT, &ia)?;
2281 let rust_value_from_java: Vec<i32> = jvm.to_rust(java_instance)?;
2282 assert_eq!(rust_value_from_java, rust_value);
2283
2284 Ok(())
2285 }
2286
2287 #[test]
2288 fn test_long_array_to_rust() -> errors::Result<()> {
2289 let jvm = create_tests_jvm()?;
2290 let rust_value: Vec<i64> = vec![-100_000, -1_000_000, 1_000_000];
2291 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2292 let java_instance = jvm.create_java_array(PRIMITIVE_LONG, &ia)?;
2293 let rust_value_from_java: Vec<i64> = jvm.to_rust(java_instance)?;
2294 assert_eq!(rust_value_from_java, rust_value);
2295
2296 Ok(())
2297 }
2298
2299 #[test]
2300 fn test_float_array_to_rust() -> errors::Result<()> {
2301 let jvm = create_tests_jvm()?;
2302 let rust_value: Vec<f32> = vec![3_f32, 7.5_f32, -1000.5_f32];
2303 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2304 let java_instance = jvm.create_java_array(PRIMITIVE_FLOAT, &ia)?;
2305 let rust_value_from_java: Vec<f32> = jvm.to_rust(java_instance)?;
2306 assert_eq!(rust_value_from_java, rust_value);
2307
2308 Ok(())
2309 }
2310
2311 #[test]
2312 fn test_double_array_to_rust() -> errors::Result<()> {
2313 let jvm = create_tests_jvm()?;
2314 let rust_value: Vec<f64> = vec![3_f64, 7.5_f64, -1000.5_f64];
2315 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2316 let java_instance = jvm.create_java_array(PRIMITIVE_DOUBLE, &ia)?;
2317 let rust_value_from_java: Vec<f64> = jvm.to_rust(java_instance)?;
2318 assert_eq!(rust_value_from_java, rust_value);
2319
2320 Ok(())
2321 }
2322
2323 #[test]
2324 fn test_boolean_array_to_rust() -> errors::Result<()> {
2325 let jvm = create_tests_jvm()?;
2326 let rust_value: Vec<bool> = vec![false, true, false];
2327 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2328 let java_instance = jvm.create_java_array(PRIMITIVE_BOOLEAN, &ia)?;
2329 let rust_value_from_java: Vec<bool> = jvm.to_rust(java_instance)?;
2330 assert_eq!(rust_value_from_java, rust_value);
2331
2332 Ok(())
2333 }
2334
2335 #[test]
2336 fn test_int_to_rust() -> errors::Result<()> {
2337 let jvm = create_tests_jvm()?;
2338 let rust_value: i32 = 3;
2339 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2340 let java_instance = jvm.create_instance(CLASS_INTEGER, &[ia])?;
2341 let java_primitive_instance = jvm.invoke(&java_instance, "intValue", InvocationArg::empty())?;
2342 let rust_value_from_java: i32 = jvm.to_rust(java_instance)?;
2343 assert_eq!(rust_value_from_java, rust_value);
2344 let rust_value_from_java: i32 = jvm.to_rust(java_primitive_instance)?;
2345 assert_eq!(rust_value_from_java, rust_value);
2346
2347 Ok(())
2348 }
2349
2350 #[test]
2351 fn test_byte_to_rust() -> errors::Result<()> {
2352 let jvm = create_tests_jvm()?;
2353 let rust_value: i8 = 3;
2354 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2355 let java_instance = jvm.create_instance(CLASS_BYTE, &[ia])?;
2356 let java_primitive_instance = jvm.invoke(&java_instance, "byteValue", InvocationArg::empty())?;
2357 let rust_value_from_java: i8 = jvm.to_rust(java_instance)?;
2358 assert_eq!(rust_value_from_java, rust_value);
2359 let rust_value_from_java: i8 = jvm.to_rust(java_primitive_instance)?;
2360 assert_eq!(rust_value_from_java, rust_value);
2361
2362 Ok(())
2363 }
2364
2365 #[test]
2366 fn test_short_to_rust() -> errors::Result<()> {
2367 let jvm = create_tests_jvm()?;
2368 let rust_value: i16 = 3;
2369 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2370 let java_instance = jvm.create_instance(CLASS_SHORT, &[ia])?;
2371 let java_primitive_instance = jvm.invoke(&java_instance, "shortValue", InvocationArg::empty())?;
2372 let rust_value_from_java: i16 = jvm.to_rust(java_instance)?;
2373 assert_eq!(rust_value_from_java, rust_value);
2374 let rust_value_from_java: i16 = jvm.to_rust(java_primitive_instance)?;
2375 assert_eq!(rust_value_from_java, rust_value);
2376
2377 Ok(())
2378 }
2379
2380 #[test]
2381 fn test_char_to_rust() -> errors::Result<()> {
2382 let jvm = create_tests_jvm()?;
2383 let rust_value: u16 = 3;
2384 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2385 let java_instance = jvm.create_instance(CLASS_CHARACTER, &[ia])?;
2386 let java_primitive_instance = jvm.invoke(&java_instance, "charValue", InvocationArg::empty())?;
2387 let rust_value_from_java: u16 = jvm.to_rust(java_instance)?;
2388 assert_eq!(rust_value_from_java, rust_value);
2389 let rust_value_from_java: u16 = jvm.to_rust(java_primitive_instance)?;
2390 assert_eq!(rust_value_from_java, rust_value);
2391
2392 Ok(())
2393 }
2394
2395 #[test]
2396 fn test_long_to_rust() -> errors::Result<()> {
2397 let jvm = create_tests_jvm()?;
2398 let rust_value: i64 = 3;
2399 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2400 let java_instance = jvm.create_instance(CLASS_LONG, &[ia])?;
2401 let java_primitive_instance = jvm.invoke(&java_instance, "longValue", InvocationArg::empty())?;
2402 let rust_value_from_java: i64 = jvm.to_rust(java_instance)?;
2403 assert_eq!(rust_value_from_java, rust_value);
2404 let rust_value_from_java: i64 = jvm.to_rust(java_primitive_instance)?;
2405 assert_eq!(rust_value_from_java, rust_value);
2406
2407 Ok(())
2408 }
2409
2410 #[test]
2411 fn test_float_to_rust() -> errors::Result<()> {
2412 let jvm = create_tests_jvm()?;
2413 let rust_value: f32 = 3.3;
2414 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2415 let java_instance = jvm.create_instance(CLASS_FLOAT, &[ia])?;
2416 let java_primitive_instance = jvm.invoke(&java_instance, "floatValue", InvocationArg::empty())?;
2417 let rust_value_from_java: f32 = jvm.to_rust(java_instance)?;
2418 assert_eq!(rust_value_from_java, rust_value);
2419 let rust_value_from_java: f32 = jvm.to_rust(java_primitive_instance)?;
2420 assert_eq!(rust_value_from_java, rust_value);
2421
2422 Ok(())
2423 }
2424
2425 #[test]
2426 fn test_double_to_rust() -> errors::Result<()> {
2427 let jvm = create_tests_jvm()?;
2428 let rust_value: f64 = 3.3;
2429 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2430 let java_instance = jvm.create_instance(CLASS_DOUBLE, &[ia])?;
2431 let java_primitive_instance = jvm.invoke(&java_instance, "doubleValue", InvocationArg::empty())?;
2432 let rust_value_from_java: f64 = jvm.to_rust(java_instance)?;
2433 assert_eq!(rust_value_from_java, rust_value);
2434 let rust_value_from_java: f64 = jvm.to_rust(java_primitive_instance)?;
2435 assert_eq!(rust_value_from_java, rust_value);
2436
2437 Ok(())
2438 }
2439
2440 #[test]
2441 fn api_by_ref_or_value() -> errors::Result<()> {
2442 let jvm = create_tests_jvm()?;
2443
2444 let inv_arg1 = InvocationArg::try_from("some string")?;
2446 let _ = jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", &[&inv_arg1])?;
2447 let _ = jvm.create_instance("java.lang.String", &[inv_arg1])?;
2448 Ok(())
2449 }
2450
2451 #[test]
2452 fn exception_string_in_the_result() -> errors::Result<()> {
2453 let jvm = create_tests_jvm()?;
2454
2455 let res = jvm.create_instance("non.Existing", InvocationArg::empty());
2456 assert!(res.is_err());
2457 let exception_sttring = format!("{}",res.err().unwrap());
2458 assert!(exception_sttring.contains("Cannot create instance of non.Existing"));
2459
2460 Ok(())
2461 }
2462}