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 pub fn java_list<'a>(
628 &self,
629 inner_class_name: impl Into<&'a str>,
630 inv_args: Vec<impl TryInto<InvocationArg, Error=J4RsError>>,
631 ) -> errors::Result<Instance> {
632 let v: Result<Vec<InvocationArg>, J4RsError> =
633 inv_args.into_iter().map(|arg| arg.try_into()).collect();
634 Self::do_create_java_list(self.jni_env, inner_class_name.into(), v?.as_ref())
635 }
636
637 fn do_create_java_list(
638 jni_env: *mut JNIEnv,
639 class_name: &str,
640 inv_args: &[InvocationArg],
641 ) -> errors::Result<Instance> {
642 debug(&format!(
643 "Creating a java list of class {} with {} elements",
644 class_name,
645 inv_args.len()
646 ));
647 unsafe {
648 let class_name_jstring: jstring =
650 jni_utils::global_jobject_from_str(class_name, jni_env)?;
651
652 let size = inv_args.len() as i32;
654 let array_ptr = {
655 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
656 jni_env,
657 size,
658 cache::get_invocation_arg_class()?,
659 ptr::null_mut(),
660 );
661 jni_utils::create_global_ref_from_local_ref(j, jni_env)?
662 };
663 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
664
665 for i in 0..size {
667 let inv_arg_java = inv_args[i as usize].as_java_ptr_with_global_ref(jni_env)?;
669 (opt_to_res(cache::get_jni_set_object_array_element())?)(
671 jni_env,
672 array_ptr,
673 i,
674 inv_arg_java,
675 );
676 inv_arg_jobjects.push(inv_arg_java);
677 }
678 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
681 jni_env,
682 cache::get_factory_class()?,
683 cache::get_factory_create_java_list_method()?,
684 class_name_jstring,
685 array_ptr,
686 );
687
688 Self::do_return(jni_env, ())?;
690
691 let java_instance_global_instance =
692 jni_utils::create_global_ref_from_local_ref(java_instance, jni_env)?;
693 for inv_arg_jobject in inv_arg_jobjects {
695 jni_utils::delete_java_ref(jni_env, inv_arg_jobject);
696 }
697 jni_utils::delete_java_ref(jni_env, array_ptr);
698 jni_utils::delete_java_ref(jni_env, class_name_jstring);
699
700 Self::do_return(
702 jni_env,
703 Instance {
704 jinstance: java_instance_global_instance,
705 class_name: class_name.to_string(),
706 skip_deleting_jobject: false,
707 },
708 )
709 }
710 }
711
712 pub fn java_map<'a>(
714 &self,
715 key_class_name: impl Into<&'a str>,
716 value_class_name: impl Into<&'a str>,
717 inv_args: HashMap<
718 impl TryInto<InvocationArg, Error=J4RsError>,
719 impl TryInto<InvocationArg, Error=J4RsError>,
720 >,
721 ) -> errors::Result<Instance> {
722 let mut inv_args_results: Vec<Result<InvocationArg, J4RsError>> =
723 Vec::with_capacity(inv_args.len() * 2);
724 let mut i = 0;
725 let mut inv_args = inv_args;
726
727 for (key, val) in inv_args.drain() {
728 inv_args_results.insert(i, key.try_into());
729 i += 1;
730 inv_args_results.insert(i, val.try_into());
731 i += 1;
732 }
733 let inv_args: Result<Vec<InvocationArg>, J4RsError> = inv_args_results
734 .into_iter()
735 .map(|arg| arg.try_into())
736 .collect();
737 Self::do_create_java_map(
738 self.jni_env,
739 key_class_name.into(),
740 value_class_name.into(),
741 inv_args?.as_ref(),
742 )
743 }
744
745 fn do_create_java_map(
746 jni_env: *mut JNIEnv,
747 key_class_name: &str,
748 value_class_name: &str,
749 inv_args: &[InvocationArg],
750 ) -> errors::Result<Instance> {
751 debug(&format!(
752 "Creating a java map with keys of class {} and values of class {} with {} elements",
753 key_class_name,
754 value_class_name,
755 inv_args.len() / 2
756 ));
757 unsafe {
758 let key_class_name_jstring: jstring =
760 jni_utils::global_jobject_from_str(key_class_name, jni_env)?;
761 let value_class_name_jstring: jstring =
763 jni_utils::global_jobject_from_str(value_class_name, jni_env)?;
764
765 let size = inv_args.len() as i32;
767 let array_ptr = {
768 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
769 jni_env,
770 size,
771 cache::get_invocation_arg_class()?,
772 ptr::null_mut(),
773 );
774 jni_utils::create_global_ref_from_local_ref(j, jni_env)?
775 };
776 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
777
778 for i in 0..size {
780 let inv_arg_java = inv_args[i as usize].as_java_ptr_with_global_ref(jni_env)?;
782 (opt_to_res(cache::get_jni_set_object_array_element())?)(
784 jni_env,
785 array_ptr,
786 i,
787 inv_arg_java,
788 );
789 inv_arg_jobjects.push(inv_arg_java);
790 }
791 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
795 jni_env,
796 cache::get_factory_class()?,
797 cache::get_factory_create_java_map_method()?,
798 key_class_name_jstring,
799 value_class_name_jstring,
800 array_ptr,
801 );
802
803 Self::do_return(jni_env, ())?;
805
806 let java_instance_global_instance =
807 jni_utils::create_global_ref_from_local_ref(java_instance, jni_env)?;
808 for inv_arg_jobject in inv_arg_jobjects {
810 jni_utils::delete_java_ref(jni_env, inv_arg_jobject);
811 }
812 jni_utils::delete_java_ref(jni_env, array_ptr);
813 jni_utils::delete_java_ref(jni_env, value_class_name_jstring);
814 jni_utils::delete_java_ref(jni_env, key_class_name_jstring);
815
816 Self::do_return(
818 jni_env,
819 Instance {
820 jinstance: java_instance_global_instance,
821 class_name: "".to_string(),
822 skip_deleting_jobject: false,
823 },
824 )
825 }
826 }
827
828 pub fn invoke(
830 &self,
831 instance: &Instance,
832 method_name: &str,
833 inv_args: &[impl Borrow<InvocationArg>],
834 ) -> errors::Result<Instance> {
835 debug(&format!(
836 "Invoking method {} of class {} using {} arguments",
837 method_name,
838 instance.class_name,
839 inv_args.len()
840 ));
841 unsafe {
842 let method_name_jstring: jstring =
844 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
845
846 let size = inv_args.len() as i32;
848 let array_ptr = {
849 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
850 self.jni_env,
851 size,
852 cache::get_invocation_arg_class()?,
853 ptr::null_mut(),
854 );
855 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
856 };
857 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
858
859 for i in 0..size {
861 let inv_arg_java =
863 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
864 (opt_to_res(cache::get_jni_set_object_array_element())?)(
866 self.jni_env,
867 array_ptr,
868 i,
869 inv_arg_java,
870 );
871 inv_arg_jobjects.push(inv_arg_java);
872 }
873
874 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
876 self.jni_env,
877 instance.jinstance,
878 cache::get_invoke_method()?,
879 method_name_jstring,
880 array_ptr,
881 );
882
883 Self::do_return(self.jni_env, ())?;
885
886 let java_instance_global_instance =
887 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
888 for inv_arg_jobject in inv_arg_jobjects {
890 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
891 }
892 jni_utils::delete_java_ref(self.jni_env, array_ptr);
893 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
894
895 Self::do_return(
897 self.jni_env,
898 Instance {
899 jinstance: java_instance_global_instance,
900 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
901 skip_deleting_jobject: false,
902 },
903 )
904 }
905 }
906
907 pub fn field(&self, instance: &Instance, field_name: &str) -> errors::Result<Instance> {
909 debug(&format!(
910 "Retrieving field {} of class {}",
911 field_name, instance.class_name
912 ));
913 unsafe {
914 let field_name_jstring: jstring =
916 jni_utils::global_jobject_from_str(field_name, self.jni_env)?;
917
918 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
920 self.jni_env,
921 instance.jinstance,
922 cache::get_field_method()?,
923 field_name_jstring,
924 );
925
926 Self::do_return(self.jni_env, ())?;
928
929 let java_instance_global_instance =
930 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
931 jni_utils::delete_java_ref(self.jni_env, field_name_jstring);
933
934 Self::do_return(
936 self.jni_env,
937 Instance {
938 jinstance: java_instance_global_instance,
939 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
940 skip_deleting_jobject: false,
941 },
942 )
943 }
944 }
945
946 pub fn static_class_field(
948 &self,
949 class_name: &str,
950 field_name: &str,
951 ) -> errors::Result<Instance> {
952 debug(&format!(
953 "Retrieving field {} of static class {}",
954 field_name, class_name
955 ));
956 let i = self.static_class(class_name)?;
957 self.field(&i, field_name)
958 }
959
960 pub fn invoke_to_channel(
963 &self,
964 instance: &Instance,
965 method_name: &str,
966 inv_args: &[impl Borrow<InvocationArg>],
967 ) -> errors::Result<InstanceReceiver> {
968 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()));
969 unsafe {
970 let (sender, rx) = channel();
972 let tx = Box::new(sender);
973 let raw_ptr = Box::into_raw(tx);
975 let address_string = format!("{:p}", raw_ptr);
977 let address = u64::from_str_radix(&address_string[2..], 16).unwrap();
978
979 let method_name_jstring: jstring =
981 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
982
983 let size = inv_args.len() as i32;
985 let array_ptr = {
986 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
987 self.jni_env,
988 size,
989 cache::get_invocation_arg_class()?,
990 ptr::null_mut(),
991 );
992 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
993 };
994 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
995
996 for i in 0..size {
998 let inv_arg_java =
1000 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
1001 (opt_to_res(cache::get_jni_set_object_array_element())?)(
1003 self.jni_env,
1004 array_ptr,
1005 i,
1006 inv_arg_java,
1007 );
1008 inv_arg_jobjects.push(inv_arg_java);
1009 }
1010
1011 (opt_to_res(cache::get_jni_call_void_method())?)(
1013 self.jni_env,
1014 instance.jinstance,
1015 cache::get_invoke_to_channel_method()?,
1016 address,
1017 method_name_jstring,
1018 array_ptr,
1019 );
1020
1021 Self::do_return(self.jni_env, ())?;
1023
1024 for inv_arg_jobject in inv_arg_jobjects {
1026 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
1027 }
1028 jni_utils::delete_java_ref(self.jni_env, array_ptr);
1029 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
1030
1031 Self::do_return(self.jni_env, InstanceReceiver::new(rx, address))
1033 }
1034 }
1035
1036 pub fn init_callback_channel(&self, instance: &Instance) -> errors::Result<InstanceReceiver> {
1040 debug("Initializing callback channel");
1041 unsafe {
1042 let (sender, rx) = channel();
1044 let tx = Box::new(sender);
1045 let raw_ptr = Box::into_raw(tx);
1047 let address_string = format!("{:p}", raw_ptr);
1049 let address = u64::from_str_radix(&address_string[2..], 16).unwrap();
1050
1051 (opt_to_res(cache::get_jni_call_void_method())?)(
1053 self.jni_env,
1054 instance.jinstance,
1055 cache::get_init_callback_channel_method()?,
1056 address,
1057 );
1058
1059 Self::do_return(self.jni_env, InstanceReceiver::new(rx, address))
1061 }
1062 }
1063
1064 pub fn invoke_static(
1066 &self,
1067 class_name: &str,
1068 method_name: &str,
1069 inv_args: &[impl Borrow<InvocationArg>],
1070 ) -> errors::Result<Instance> {
1071 debug(&format!(
1072 "Invoking static method {} of class {} using {} arguments",
1073 method_name,
1074 class_name,
1075 inv_args.len()
1076 ));
1077 unsafe {
1078 let class_name_jstring: jstring =
1080 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
1081 let tmp_java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1084 self.jni_env,
1085 cache::get_factory_class()?,
1086 cache::get_factory_create_for_static_method()?,
1087 class_name_jstring,
1088 );
1089
1090 let method_name_jstring: jstring =
1092 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
1093
1094 let size = inv_args.len() as i32;
1096 let array_ptr = {
1097 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
1098 self.jni_env,
1099 size,
1100 cache::get_invocation_arg_class()?,
1101 ptr::null_mut(),
1102 );
1103 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
1104 };
1105 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
1106 for i in 0..size {
1108 let inv_arg_java =
1110 inv_args[i as usize].borrow().as_java_ptr_with_global_ref(self.jni_env)?;
1111 (opt_to_res(cache::get_jni_set_object_array_element())?)(
1113 self.jni_env,
1114 array_ptr,
1115 i,
1116 inv_arg_java,
1117 );
1118 inv_arg_jobjects.push(inv_arg_java);
1119 }
1120 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1122 self.jni_env,
1123 tmp_java_instance,
1124 cache::get_invoke_static_method()?,
1125 method_name_jstring,
1126 array_ptr,
1127 );
1128 jni_utils::delete_java_local_ref(self.jni_env, tmp_java_instance);
1130 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
1131 Self::do_return(self.jni_env, ())?;
1133
1134 for inv_arg_jobject in inv_arg_jobjects {
1136 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
1137 }
1138 jni_utils::delete_java_ref(self.jni_env, array_ptr);
1139 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
1140
1141 Self::do_return(
1143 self.jni_env,
1144 Instance::from_jobject_with_global_ref(java_instance)?,
1145 )
1146 }
1147 }
1148
1149 pub fn clone_instance(&self, instance: &Instance) -> errors::Result<Instance> {
1151 unsafe {
1152 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1154 self.jni_env,
1155 cache::get_class_to_invoke_clone_and_cast()?,
1156 cache::get_clone_static_method()?,
1157 instance.jinstance,
1158 );
1159
1160 Self::do_return(
1162 self.jni_env,
1163 Instance::from_jobject_with_global_ref(java_instance)?,
1164 )
1165 }
1166 }
1167
1168 pub fn cast(&self, from_instance: &Instance, to_class: &str) -> errors::Result<Instance> {
1170 debug(&format!("Casting to class {}", to_class));
1171 unsafe {
1172 let to_class_jstring: jstring =
1175 jni_utils::global_jobject_from_str(to_class, self.jni_env)?;
1176
1177 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1179 self.jni_env,
1180 cache::get_class_to_invoke_clone_and_cast()?,
1181 cache::get_cast_static_method()?,
1182 from_instance.jinstance,
1183 to_class_jstring,
1184 );
1185
1186 Self::do_return(self.jni_env, ())?;
1188
1189 jni_utils::delete_java_ref(self.jni_env, to_class_jstring);
1191
1192 Self::do_return(
1194 self.jni_env,
1195 Instance::from_jobject_with_global_ref(java_instance)?,
1196 )
1197 }
1198 }
1199
1200 pub fn check_equals(&self, instance: impl Borrow<Instance>, inv_arg: impl Borrow<InvocationArg>) -> errors::Result<bool> {
1205 debug(&format!("Checking equality between instances of {} and {}", instance.borrow().class_name(), inv_arg.borrow().class_name()));
1206 unsafe {
1207 let inv_arg_java_b = inv_arg.borrow().as_java_ptr_with_global_ref(self.jni_env)?;
1209 let java_boolean = (opt_to_res(cache::get_jni_call_boolean_method())?)(
1211 self.jni_env,
1212 instance.borrow().jinstance,
1213 cache::get_check_equals_method()?,
1214 inv_arg_java_b,
1215 );
1216
1217 Self::do_return(
1219 self.jni_env,
1220 java_boolean,
1221 )
1222 }
1223 }
1224
1225 pub fn instance_into_raw_object(&self, instance: Instance) -> errors::Result<jobject> {
1227 debug(&format!("Getting the raw jobject from instance of class {}", instance.borrow().class_name()));
1228 let object_instance = unsafe {
1230 (opt_to_res(cache::get_jni_call_object_method())?)(
1231 self.jni_env,
1232 instance.jinstance,
1233 cache::get_get_object_method()?,
1234 )};
1235
1236 Self::do_return(
1237 self.jni_env,
1238 object_instance,
1239 )
1240 }
1241
1242 pub fn into_raw(self) -> *mut JNIEnv {
1244 debug("Getting the raw JNIEnv from the Jvm");
1245
1246 self.jni_env
1247 }
1248
1249 pub fn to_rust_boxed<T>(&self, instance: Instance) -> errors::Result<Box<T>>
1251 where
1252 T: DeserializeOwned + Any,
1253 {
1254 macro_rules! rust_box_from_java_object {
1256 ($jni_transformation:path) => {{
1257 let object_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1259 self.jni_env,
1260 instance.jinstance,
1261 cache::get_get_object_method()?,
1262 );
1263 let object_instance =
1264 jni_utils::create_global_ref_from_local_ref(object_instance, self.jni_env)?;
1265 let v = Box::new($jni_transformation(object_instance, self.jni_env)?);
1266 let v_any = v as Box<dyn Any>;
1267
1268 jni_utils::delete_java_ref(self.jni_env, object_instance);
1269
1270 match v_any.downcast::<T>() {
1271 Ok(v) => Ok(v),
1272 Err(error) => Err(errors::J4RsError::RustError(format!(
1273 "Could not downcast to Rust type: {:?}",
1274 error
1275 ))),
1276 }
1277 }};
1278 }
1279
1280 let t_type = TypeId::of::<T>();
1281
1282
1283 unsafe {
1284 let object_class_name_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1286 self.jni_env,
1287 instance.jinstance,
1288 cache::get_get_object_class_name_method()?,
1289 );
1290 let object_class_name_instance = jni_utils::create_global_ref_from_local_ref(
1291 object_class_name_instance,
1292 self.jni_env,
1293 )?;
1294 let class_name = &(jni_utils::string_from_jobject(object_class_name_instance, self.jni_env)?);
1295 jni_utils::delete_java_ref(self.jni_env, object_class_name_instance);
1296 if t_type == TypeId::of::<String>() && JavaClass::String.get_class_str() == class_name {
1297 rust_box_from_java_object!(jni_utils::string_from_jobject)
1298 } else if t_type == TypeId::of::<i32>()
1299 && (JavaClass::Integer.get_class_str() == class_name || PRIMITIVE_INT == class_name)
1300 {
1301 rust_box_from_java_object!(jni_utils::i32_from_jobject)
1302 } else if t_type == TypeId::of::<i8>()
1303 && (JavaClass::Byte.get_class_str() == class_name || PRIMITIVE_BYTE == class_name)
1304 {
1305 rust_box_from_java_object!(jni_utils::i8_from_jobject)
1306 } else if t_type == TypeId::of::<i16>()
1307 && (JavaClass::Short.get_class_str() == class_name || PRIMITIVE_SHORT == class_name)
1308 {
1309 rust_box_from_java_object!(jni_utils::i16_from_jobject)
1310 } else if t_type == TypeId::of::<u16>()
1311 && (JavaClass::Character.get_class_str() == class_name || PRIMITIVE_CHAR == class_name)
1312 {
1313 rust_box_from_java_object!(jni_utils::u16_from_jobject)
1314 } else if t_type == TypeId::of::<i64>()
1315 && (JavaClass::Long.get_class_str() == class_name || PRIMITIVE_LONG == class_name)
1316 {
1317 rust_box_from_java_object!(jni_utils::i64_from_jobject)
1318 } else if t_type == TypeId::of::<f32>()
1319 && (JavaClass::Float.get_class_str() == class_name || PRIMITIVE_FLOAT == class_name)
1320 {
1321 rust_box_from_java_object!(jni_utils::f32_from_jobject)
1322 } else if t_type == TypeId::of::<f64>()
1323 && (JavaClass::Double.get_class_str() == class_name
1324 || PRIMITIVE_DOUBLE == class_name)
1325 {
1326 rust_box_from_java_object!(jni_utils::f64_from_jobject)
1327 } else if t_type == TypeId::of::<Vec<i8>>()
1328 && PRIMITIVE_BYTE_ARRAY == class_name
1329 {
1330 rust_box_from_java_object!(jni_utils::i8_array_from_jobject)
1331 } else if t_type == TypeId::of::<Vec<i16>>()
1332 && PRIMITIVE_SHORT_ARRAY == class_name
1333 {
1334 rust_box_from_java_object!(jni_utils::i16_array_from_jobject)
1335 } else if t_type == TypeId::of::<Vec<u16>>()
1336 && PRIMITIVE_CHAR_ARRAY == class_name
1337 {
1338 rust_box_from_java_object!(jni_utils::u16_array_from_jobject)
1339 } else if t_type == TypeId::of::<Vec<i32>>()
1340 && PRIMITIVE_INT_ARRAY == class_name
1341 {
1342 rust_box_from_java_object!(jni_utils::i32_array_from_jobject)
1343 } else if t_type == TypeId::of::<Vec<i64>>()
1344 && PRIMITIVE_LONG_ARRAY == class_name
1345 {
1346 rust_box_from_java_object!(jni_utils::i64_array_from_jobject)
1347 } else if t_type == TypeId::of::<Vec<f32>>()
1348 && PRIMITIVE_FLOAT_ARRAY == class_name
1349 {
1350 rust_box_from_java_object!(jni_utils::f32_array_from_jobject)
1351 } else if t_type == TypeId::of::<Vec<f64>>()
1352 && PRIMITIVE_DOUBLE_ARRAY == class_name
1353 {
1354 rust_box_from_java_object!(jni_utils::f64_array_from_jobject)
1355 } else if t_type == TypeId::of::<Vec<bool>>()
1356 && PRIMITIVE_BOOLEAN_ARRAY == class_name
1357 {
1358 rust_box_from_java_object!(jni_utils::boolean_array_from_jobject)
1359 } else {
1360 Ok(Box::new(self.to_rust_deserialized(instance)?))
1361 }
1362 }
1363 }
1364
1365 pub fn to_rust<T>(&self, instance: Instance) -> errors::Result<T>
1367 where
1368 T: DeserializeOwned + Any,
1369 {
1370 self.to_rust_boxed(instance).map(|v| *v)
1371 }
1372
1373 pub fn to_rust_deserialized<T>(&self, instance: Instance) -> errors::Result<T>
1374 where
1375 T: DeserializeOwned + Any,
1376 {
1377 unsafe {
1378 debug("Invoking the getJson method");
1379 let json_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1381 self.jni_env,
1382 instance.jinstance,
1383 cache::get_get_json_method()?,
1384 );
1385 let _ = Self::do_return(self.jni_env, "")?;
1386 debug("Transforming jstring to rust String");
1387 let global_json_instance =
1388 jni_utils::create_global_ref_from_local_ref(json_instance, self.jni_env)?;
1389 let json = jni_utils::jstring_to_rust_string(self, global_json_instance as jstring)?;
1390 jni_utils::delete_java_ref(self.jni_env, global_json_instance);
1391 Self::do_return(self.jni_env, serde_json::from_str(&json)?)
1392 }
1393 }
1394
1395 pub fn deploy_artifact<T: Any + JavaArtifact>(&self, artifact: &T) -> errors::Result<()> {
1401 let artifact = artifact as &dyn Any;
1402 if let Some(maven_artifact) = artifact.downcast_ref::<MavenArtifact>() {
1403 for repo in get_maven_settings().repos.into_iter() {
1404 let instance = self.create_instance(
1405 "org.astonbitecode.j4rs.api.deploy.SimpleMavenDeployer",
1406 &[InvocationArg::try_from(repo.uri)?,
1407 InvocationArg::try_from(&maven_artifact.base)?],
1408 )?;
1409
1410 let res = self.invoke(
1411 &instance,
1412 "deploy",
1413 &vec![
1414 InvocationArg::try_from(&maven_artifact.group)?,
1415 InvocationArg::try_from(&maven_artifact.id)?,
1416 InvocationArg::try_from(&maven_artifact.version)?,
1417 InvocationArg::try_from(&maven_artifact.qualifier)?,
1418 ],
1419 );
1420
1421 if res.is_ok() {
1422 break;
1423 }
1424 }
1425
1426 Ok(())
1427 } else if let Some(local_jar_artifact) = artifact.downcast_ref::<LocalJarArtifact>() {
1428 let instance = self.create_instance(
1429 "org.astonbitecode.j4rs.api.deploy.FileSystemDeployer",
1430 &[InvocationArg::try_from(&local_jar_artifact.base)?],
1431 )?;
1432
1433 let _ = self.invoke(
1434 &instance,
1435 "deploy",
1436 &[InvocationArg::try_from(&local_jar_artifact.path)?],
1437 )?;
1438 Ok(())
1439 } else {
1440 Err(J4RsError::GeneralError(format!(
1441 "Don't know how to deploy artifacts of {:?}",
1442 artifact.type_id()
1443 )))
1444 }
1445 }
1446
1447 pub fn copy_j4rs_libs_under<P: AsRef<Path>>(path: P) -> errors::Result<()> {
1453 let mut pb = PathBuf::from(path.as_ref());
1454 pb.push("deps");
1455 fs::create_dir_all(&pb)?;
1456
1457 let default_jassets_path_buf = utils::default_jassets_path()?;
1458 let default_jassets_path_string = default_jassets_path_buf.to_str().unwrap().to_owned();
1459
1460 let options = &mut fs_extra::dir::CopyOptions::new();
1462 options.overwrite = true;
1463 let _ = fs_extra::copy_items(vec![default_jassets_path_string].as_ref(), path, options)?;
1464
1465 let dynlibs: Vec<String> = {
1467 let mut dynlibs = vec![];
1468 for _i in 0..10 {
1471 dynlibs = utils::find_j4rs_dynamic_libraries_paths()?;
1472 if dynlibs.is_empty() {
1473 thread::sleep(time::Duration::from_millis(1000));
1474 } else {
1475 break;
1476 }
1477 }
1478 dynlibs
1479 };
1480 if dynlibs.is_empty() {
1481 let message = format!(
1482 "No j4rs dynamic libraries found for target triple {}. \
1483 The host triple during build is {}.",
1484 env::var("TARGET").unwrap_or("".to_string()),
1485 env::var("HOST").unwrap_or("UNKNOWN".to_string())
1486 );
1487 println!("cargo:warning={}", message);
1488 }
1489
1490 let _ = fs_extra::copy_items(&dynlibs, &pb, options)?;
1491
1492 Ok(())
1493 }
1494
1495 pub fn chain(&self, instance: &Instance) -> errors::Result<ChainableInstance<'_>> {
1497 ChainableInstance::new_with_instance_ref(instance, self)
1498 }
1499
1500 pub fn into_chain(&self, instance: Instance) -> ChainableInstance<'_> {
1502 ChainableInstance::new(instance, self)
1503 }
1504
1505 pub fn throw_invocation_exception(&self, message: &str) -> errors::Result<()> {
1507 unsafe {
1508 let _ = jni_utils::throw_exception(message, self.jni_env)?;
1509 }
1510 Ok(())
1511 }
1512
1513 pub(crate) fn do_return<T>(jni_env: *mut JNIEnv, to_return: T) -> errors::Result<T> {
1514 unsafe {
1515 if (opt_to_res(cache::get_jni_exception_check())?)(jni_env) == JNI_TRUE {
1516 let throwable = (opt_to_res(cache::get_jni_exception_occured())?)(jni_env);
1517 let throwable_string = Self::get_throwable_string(throwable, jni_env)?;
1518 (opt_to_res(cache::get_jni_exception_clear())?)(jni_env);
1519 Err(J4RsError::JavaError(throwable_string))
1520 } else {
1521 Ok(to_return)
1522 }
1523 }
1524 }
1525
1526 unsafe fn get_throwable_string(throwable: jobject, jni_env: *mut JNIEnv) -> errors::Result<String> {
1527 let java_string = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1528 jni_env,
1529 cache::get_utils_class()?,
1530 cache::get_utils_exception_to_string_method()?,
1531 throwable,
1532 );
1533 let to_ret = jni_utils::string_from_jobject(java_string, jni_env);
1534 jni_utils::delete_java_local_ref(jni_env, java_string);
1535 to_ret
1536 }
1537
1538 fn get_created_vm() -> Option<*mut JNIEnv> {
1540 unsafe {
1541 let mut created_vms_size: jsize = 0;
1543 tweaks::get_created_java_vms(
1544 &mut Vec::with_capacity(created_vms_size as usize),
1545 0,
1546 &mut created_vms_size,
1547 );
1548
1549 if created_vms_size == 0 {
1550 None
1551 } else {
1552 debug(&format!(
1553 "Retrieving the first of {} created JVMs",
1554 created_vms_size
1555 ));
1556 let mut buffer: Vec<*mut JavaVM> = Vec::with_capacity(2);
1558 for _ in 0..created_vms_size {
1559 buffer.push(ptr::null_mut());
1560 }
1561
1562 let retjint = tweaks::get_created_java_vms(
1563 &mut buffer,
1564 created_vms_size,
1565 &mut created_vms_size,
1566 );
1567 if retjint == JNI_OK {
1568 let act = (**buffer[0]).v1_4.AttachCurrentThread;
1569 let mut jni_environment: *mut JNIEnv = ptr::null_mut();
1570 (act)(
1571 buffer[0],
1572 (&mut jni_environment as *mut *mut JNIEnv) as *mut *mut c_void,
1573 ptr::null_mut(),
1574 );
1575 Some(jni_environment)
1576 } else {
1577 error(&format!(
1578 "Error while retrieving the created JVMs: {}",
1579 retjint
1580 ));
1581 None
1582 }
1583 }
1584 }
1585 }
1586
1587 fn detach_current_thread(&self) {
1588 unsafe {
1589 let mut created_vms_size: jsize = 0;
1591 tweaks::get_created_java_vms(
1592 &mut Vec::with_capacity(created_vms_size as usize),
1593 0,
1594 &mut created_vms_size,
1595 );
1596
1597 if created_vms_size > 0 {
1598 let mut buffer: Vec<*mut JavaVM> = Vec::with_capacity(created_vms_size as usize);
1600 for _ in 0..created_vms_size {
1601 buffer.push(ptr::null_mut());
1602 }
1603
1604 let retjint = tweaks::get_created_java_vms(
1605 &mut buffer,
1606 created_vms_size,
1607 &mut created_vms_size,
1608 );
1609 if retjint == JNI_OK {
1610 let dct = (**buffer[0]).v1_4.DetachCurrentThread;
1611 (dct)(buffer[0]);
1612 } else {
1613 warn(&format!(
1614 "Error while retrieving the created JVMs: {}",
1615 retjint
1616 ));
1617 }
1618 }
1619 }
1620 }
1621
1622 pub fn select(instance_receivers: &[&InstanceReceiver]) -> errors::Result<(usize, Instance)> {
1627 loop {
1628 for (index, ir) in instance_receivers.iter().enumerate() {
1629 let res = ir.rx.try_recv();
1630 if res.is_ok() {
1631 return Ok((index, res.unwrap()));
1632 }
1633 }
1634 thread::yield_now();
1635 }
1636 }
1637
1638 pub fn select_timeout(
1645 instance_receivers: &[&InstanceReceiver],
1646 timeout: &time::Duration,
1647 ) -> errors::Result<(usize, Instance)> {
1648 let start = time::Instant::now();
1649 loop {
1650 for (index, ir) in instance_receivers.iter().enumerate() {
1651 let res = ir.rx.try_recv();
1652 if res.is_ok() {
1653 return Ok((index, res.unwrap()));
1654 }
1655 }
1656 if &start.elapsed() > timeout {
1657 return Err(J4RsError::Timeout);
1658 }
1659 thread::yield_now();
1660 }
1661 }
1662}
1663
1664impl Drop for Jvm {
1665 fn drop(&mut self) {
1666 if cache::remove_active_jvm() <= 0 {
1667 if self.detach_thread_on_drop {
1668 self.detach_current_thread();
1669 }
1670 cache::set_thread_local_env(None);
1671 }
1672 }
1673}
1674
1675pub struct JvmBuilder<'a> {
1677 classpath_entries: Vec<ClasspathEntry>,
1678 java_opts: Vec<JavaOpt<'a>>,
1679 no_implicit_classpath: bool,
1680 detach_thread_on_drop: bool,
1681 lib_name_opt: Option<String>,
1682 skip_setting_native_lib: bool,
1683 base_path: Option<PathBuf>,
1684 maven_settings: MavenSettings,
1685 javafx: bool,
1686 default_classloader: bool,
1687 java_vm_opt: Option<*mut JavaVM>,
1688 jobject_within_valid_classloader_opt: Option<jobject>,
1689}
1690
1691impl<'a> JvmBuilder<'a> {
1692 pub fn new<'b>() -> JvmBuilder<'b> {
1694 JvmBuilder {
1695 classpath_entries: Vec::new(),
1696 java_opts: Vec::new(),
1697 no_implicit_classpath: false,
1698 detach_thread_on_drop: true,
1699 lib_name_opt: None,
1700 skip_setting_native_lib: false,
1701 base_path: None,
1702 maven_settings: MavenSettings::default(),
1703 javafx: false,
1704 default_classloader: false,
1705 java_vm_opt: None,
1706 jobject_within_valid_classloader_opt: None
1707 }
1708 }
1709
1710 pub fn classpath_entry(&'a mut self, cp_entry: ClasspathEntry) -> &'a mut JvmBuilder<'a> {
1712 self.classpath_entries.push(cp_entry);
1713 self
1714 }
1715
1716 pub fn classpath_entries(
1718 &'a mut self,
1719 cp_entries: Vec<ClasspathEntry>,
1720 ) -> &'a mut JvmBuilder<'a> {
1721 for cp_entry in cp_entries {
1722 self.classpath_entries.push(cp_entry);
1723 }
1724 self
1725 }
1726
1727 pub fn java_opt(&'a mut self, opt: JavaOpt<'a>) -> &'a mut JvmBuilder<'a> {
1729 self.java_opts.push(opt);
1730 self
1731 }
1732
1733 pub fn java_opts(&'a mut self, opts: Vec<JavaOpt<'a>>) -> &'a mut JvmBuilder<'a> {
1735 for opt in opts {
1736 self.java_opts.push(opt);
1737 }
1738 self
1739 }
1740
1741 pub fn with_no_implicit_classpath(&'a mut self) -> &'a mut JvmBuilder<'a> {
1744 self.no_implicit_classpath = true;
1745 self
1746 }
1747
1748 pub fn detach_thread_on_drop(&'a mut self, detach_thread_on_drop: bool) -> &'a mut JvmBuilder<'a> {
1754 self.detach_thread_on_drop = detach_thread_on_drop;
1755 self
1756 }
1757
1758 pub fn with_native_lib_name(&'a mut self, lib_name: &str) -> &'a mut JvmBuilder<'a> {
1763 self.lib_name_opt = Some(lib_name.to_string());
1764 self
1765 }
1766
1767 pub fn skip_setting_native_lib(&'a mut self) -> &'a mut JvmBuilder<'a> {
1770 self.skip_setting_native_lib = true;
1771 self
1772 }
1773
1774 pub fn with_base_path<P: AsRef<Path>>(&'a mut self, base_path: P) -> &'a mut JvmBuilder<'a> {
1777 self.base_path = Some(base_path.as_ref().to_owned());
1778 self
1779 }
1780
1781 pub fn with_maven_settings(&'a mut self, maven_settings: MavenSettings) -> &'a mut JvmBuilder<'a> {
1783 self.maven_settings = maven_settings;
1784 self
1785 }
1786
1787 pub fn with_javafx_support(&'a mut self) -> &'a mut JvmBuilder<'a> {
1789 self.javafx = true;
1790 self
1791 }
1792
1793 pub fn with_java_vm(&'a mut self, java_vm: *mut JavaVM) -> &'a mut JvmBuilder<'a> {
1797 self.java_vm_opt = Some(java_vm);
1798 self
1799 }
1800
1801 pub fn with_classloader_of_activity(&'a mut self, jobject_within_valid_classloader: jobject) -> &'a mut JvmBuilder<'a> {
1819 self.jobject_within_valid_classloader_opt = Some(jobject_within_valid_classloader);
1820 let tmp = self.detach_thread_on_drop(false);
1825 let tmp = tmp.with_no_implicit_classpath();
1826 tmp
1827 }
1828
1829 pub fn with_default_classloader(&'a mut self) -> &'a mut JvmBuilder<'a> {
1853 self.default_classloader = true;
1854 self
1855 }
1856
1857 pub fn build(&mut self) -> errors::Result<Jvm> {
1859 if !self.default_classloader {
1860 self.java_opts.push(JavaOpt::new(
1862 "-Djava.system.class.loader=org.astonbitecode.j4rs.api.deploy.J4rsClassLoader",
1863 ));
1864 self.java_opts.push(JavaOpt::new("-Xshare:off"));
1865 self.java_opts.push(JavaOpt::new(
1866 "-Djdk.net.URLClassPath.showIgnoredClassPathEntries=true",
1867 ));
1868 }
1869
1870 let classpath = if self.no_implicit_classpath {
1871 self.classpath_entries
1872 .iter()
1873 .fold(".".to_string(), |all, elem| {
1874 format!("{}{}{}", all, utils::classpath_sep(), elem.to_string())
1875 })
1876 } else {
1877 let jassets_path = self.get_jassets_path()?;
1879 let j4rs_jar_to_use = format!("j4rs-{}-jar-with-dependencies.jar", j4rs_version());
1881 let j4rs_testing_jar_to_use = format!("j4rs-testing-{}.jar", j4rs_version());
1882 let j4rs_javafx_jar_to_use = format!("j4rs-javafx-{}.jar", j4rs_version());
1883 let mut cp_string = String::new();
1885 for entry in std::fs::read_dir(jassets_path)? {
1886 let path = entry?.path();
1887 if let Some(file_name) = opt_to_res(path.file_name())?.to_str() {
1888 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) {
1889 if !cp_string.is_empty() {
1890 cp_string.push_str(utils::classpath_sep());
1891 }
1892 if let Some(path) = path.to_str() {
1893 cp_string.push_str(path);
1894 }
1895 }
1896 }
1897 }
1898
1899 let default_class_path = format!("-Djava.class.path={}", cp_string);
1900
1901 self.classpath_entries
1902 .iter()
1903 .fold(default_class_path, |all, elem| {
1904 format!("{}{}{}", all, utils::classpath_sep(), elem.to_string())
1905 })
1906 };
1907 info(&format!("Setting classpath to {}", classpath));
1908
1909 let mut jvm_options = if self.no_implicit_classpath {
1911 vec![classpath]
1912 } else {
1913 let default_library_path = utils::java_library_path()?;
1914 info(&format!("Setting library path to {}", default_library_path));
1915 vec![classpath, default_library_path]
1916 };
1917
1918 if self.javafx {
1919 let jassets_path = self.get_jassets_path()?;
1920 let jassets_path_string = jassets_path.to_str().unwrap_or(".");
1921 let modules_path = format!("--module-path {}", jassets_path_string);
1922 jvm_options.push(modules_path);
1923 jvm_options.push(
1924 "--add-modules javafx.base,javafx.controls,javafx.graphics,javafx.fxml".to_string(),
1925 );
1926 }
1927 self.java_opts
1928 .clone()
1929 .into_iter()
1930 .for_each(|opt| jvm_options.push(opt.to_string()));
1931
1932 let lib_name_opt = if self.lib_name_opt.is_none() && !self.skip_setting_native_lib && cfg!(not(target_os = "android")) {
1934 let deps_dir = utils::deps_dir()?;
1935 let found_libs: Vec<String> = if Path::new(&deps_dir).exists() {
1936 utils::find_j4rs_dynamic_libraries_names()?
1937 } else {
1938 let default_lib_name = if cfg!(windows) {
1941 "l4rs.dll".to_string()
1942 } else {
1943 "libj4rs.so".to_string()
1944 };
1945 info(&format!(
1946 "Deps directory not found. Setting the library name to search to default: {}",
1947 default_lib_name
1948 ));
1949 vec![default_lib_name]
1950 };
1951
1952 let lib_name_opt = if !found_libs.is_empty() {
1953 let a_lib = found_libs[0].clone().replace("lib", "");
1954
1955 let dot_splitted: Vec<&str> = a_lib.split('.').collect();
1956 let name = dot_splitted[0].to_string();
1957 info(&format!(
1958 "Passing to the Java world the name of the library to load: {}",
1959 name
1960 ));
1961 Some(name)
1962 } else {
1963 None
1964 };
1965 lib_name_opt
1966 } else if self.lib_name_opt.is_some() && !self.skip_setting_native_lib {
1967 let name = self.lib_name_opt.clone();
1968 info(&format!(
1969 "Passing to the Java world the name of the library to load: {}",
1970 name.as_ref().unwrap()
1971 ));
1972 name
1973 } else {
1974 None
1975 };
1976
1977 provisioning::set_maven_settings(&self.maven_settings);
1978
1979 let jvm_res = if self.java_vm_opt.is_some() {
1980 set_java_vm(self.java_vm_opt.unwrap());
1982 Jvm::attach_thread()
1983 } else {
1984 Jvm::new(&jvm_options, lib_name_opt)
1985 };
1986
1987 jvm_res.and_then(|mut jvm| {
1988 if !self.detach_thread_on_drop {
1989 jvm.detach_thread_on_drop(false);
1990 }
1991 if self.jobject_within_valid_classloader_opt.is_some() {
1992 cache_classloader_of(jvm.jni_env, self.jobject_within_valid_classloader_opt.unwrap())?;
1993 }
1994 Ok(jvm)
1995 })
1996 }
1997
1998 pub fn already_initialized() -> errors::Result<Jvm> {
2002 Jvm::new(&[], None)
2003 }
2004
2005 fn get_jassets_path(&self) -> errors::Result<PathBuf> {
2006 match &self.base_path {
2007 Some(base_path_string) => {
2008 let mut pb = PathBuf::from(base_path_string);
2009 pb.push("jassets");
2010 let mut global_jassets_path_opt = cache::JASSETS_PATH.lock()?;
2011 *global_jassets_path_opt = Some(pb.clone());
2012 Ok(pb)
2013 }
2014 None => utils::default_jassets_path(),
2015 }
2016 }
2017}
2018
2019pub enum JavaClass<'a> {
2021 Void,
2022 String,
2023 Boolean,
2024 Byte,
2025 Character,
2026 Short,
2027 Integer,
2028 Long,
2029 Float,
2030 Double,
2031 List,
2032 Of(&'a str),
2033}
2034
2035impl<'a> JavaClass<'a> {
2036 pub fn get_class_str(&self) -> &'a str {
2037 match self {
2038 Self::Void => "void",
2039 Self::String => CLASS_STRING,
2040 Self::Boolean => CLASS_BOOLEAN,
2041 Self::Byte => CLASS_BYTE,
2042 Self::Character => CLASS_CHARACTER,
2043 Self::Short => CLASS_SHORT,
2044 Self::Integer => CLASS_INTEGER,
2045 Self::Long => CLASS_LONG,
2046 Self::Float => CLASS_FLOAT,
2047 Self::Double => CLASS_DOUBLE,
2048 Self::List => CLASS_LIST,
2049 Self::Of(str) => str,
2050 }
2051 }
2052}
2053
2054impl<'a> From<JavaClass<'a>> for &'a str {
2055 fn from(java_class: JavaClass<'a>) -> &'a str {
2056 java_class.get_class_str()
2057 }
2058}
2059
2060impl<'a> From<&'a str> for JavaClass<'a> {
2061 fn from(java_class: &'a str) -> JavaClass<'a> {
2062 match java_class {
2063 "void" => Self::Void,
2064 CLASS_STRING => Self::String,
2065 CLASS_BOOLEAN => Self::Boolean,
2066 CLASS_BYTE => Self::Byte,
2067 CLASS_CHARACTER => Self::Character,
2068 CLASS_SHORT => Self::Short,
2069 CLASS_INTEGER => Self::Integer,
2070 CLASS_LONG => Self::Long,
2071 CLASS_FLOAT => Self::Float,
2072 CLASS_DOUBLE => Self::Double,
2073 CLASS_LIST => Self::List,
2074 str => Self::Of(str),
2075 }
2076 }
2077}
2078
2079pub enum Null<'a> {
2084 String,
2085 Boolean,
2086 Byte,
2087 Character,
2088 Short,
2089 Integer,
2090 Long,
2091 Float,
2092 Double,
2093 List,
2094 Of(&'a str),
2095}
2096
2097#[derive(Debug, Clone)]
2099pub struct ClasspathEntry(PathBuf);
2100
2101impl ClasspathEntry {
2102 pub fn new<P: AsRef<Path>>(classpath_entry: P) -> ClasspathEntry {
2103 ClasspathEntry(classpath_entry.as_ref().to_owned())
2104 }
2105}
2106
2107impl ToString for ClasspathEntry {
2108 fn to_string(&self) -> String {
2109 self.0.to_string_lossy().to_string()
2110 }
2111}
2112
2113#[derive(Debug, Clone)]
2115pub struct JavaOpt<'a>(&'a str);
2116
2117impl<'a> JavaOpt<'a> {
2118 pub fn new(java_opt: &str) -> JavaOpt<'_> {
2119 JavaOpt(java_opt)
2120 }
2121}
2122
2123impl<'a> ToString for JavaOpt<'a> {
2124 fn to_string(&self) -> String {
2125 self.0.to_string()
2126 }
2127}
2128
2129#[cfg(test)]
2130mod api_unit_tests {
2131 use crate::lib_unit_tests::create_tests_jvm;
2132 use super::*;
2133
2134 #[test]
2135 fn jvm_builder() -> errors::Result<()> {
2136 let res = create_tests_jvm();
2137 assert!(res.is_ok());
2138 let one_more_res = JvmBuilder::already_initialized();
2139 assert!(one_more_res.is_ok());
2140
2141 Ok(())
2142 }
2143
2144 #[test]
2145 fn test_copy_j4rs_libs_under() -> errors::Result<()> {
2146 let newdir = "./newdir";
2147 Jvm::copy_j4rs_libs_under(newdir)?;
2148
2149 let _ = std::fs::remove_dir_all(newdir);
2150
2151 Ok(())
2152 }
2153
2154 #[test]
2155 fn test_select() -> errors::Result<()> {
2156 let (tx1, rx1) = channel();
2157 let ir1 = InstanceReceiver::new(rx1, 0);
2158 let (_tx2, rx2) = channel();
2159 let ir2 = InstanceReceiver::new(rx2, 0);
2160 let (tx3, rx3) = channel();
2161 let ir3 = InstanceReceiver::new(rx3, 0);
2162
2163 thread::spawn(move || {
2164 let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2165 thread::sleep(time::Duration::from_millis(10));
2167 let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2168 thread::sleep(time::Duration::from_millis(10));
2169 let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2170 });
2171
2172 let (index1, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2173 let (index2, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2174 let (index3, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2175 assert_eq!(index1, 2);
2176 assert_eq!(index2, 0);
2177 assert_eq!(index3, 2);
2178
2179 Ok(())
2180 }
2181
2182 #[test]
2183 fn test_select_timeout() -> errors::Result<()> {
2184 let (tx1, rx1) = channel();
2185 let ir1 = InstanceReceiver::new(rx1, 0);
2186 let (tx2, rx2) = channel();
2187 let ir2 = InstanceReceiver::new(rx2, 0);
2188
2189 thread::spawn(move || {
2190 let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2191 thread::sleep(time::Duration::from_millis(10));
2193 let _ = tx2.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2194 });
2195
2196 let d = time::Duration::from_millis(500);
2197 let (index1, _) = Jvm::select_timeout(&[&ir1, &ir2], &d)?;
2198 let (index2, _) = Jvm::select_timeout(&[&ir1, &ir2], &d)?;
2199 assert!(Jvm::select_timeout(&[&ir1, &ir2], &d).is_err());
2200 assert_eq!(index1, 0);
2201 assert_eq!(index2, 1);
2202
2203 Ok(())
2204 }
2205
2206 #[test]
2207 fn test_java_class_creation() -> errors::Result<()> {
2208 assert_eq!(JavaClass::Void.get_class_str(), "void");
2209 assert_eq!(JavaClass::String.get_class_str(), CLASS_STRING);
2210 assert_eq!(JavaClass::Boolean.get_class_str(), CLASS_BOOLEAN);
2211 assert_eq!(JavaClass::Byte.get_class_str(), CLASS_BYTE);
2212 assert_eq!(JavaClass::Character.get_class_str(), CLASS_CHARACTER);
2213 assert_eq!(JavaClass::Short.get_class_str(), CLASS_SHORT);
2214 assert_eq!(JavaClass::Integer.get_class_str(), CLASS_INTEGER);
2215 assert_eq!(JavaClass::Long.get_class_str(), CLASS_LONG);
2216 assert_eq!(JavaClass::Float.get_class_str(), CLASS_FLOAT);
2217 assert_eq!(JavaClass::Double.get_class_str(), CLASS_DOUBLE);
2218 assert_eq!(JavaClass::List.get_class_str(), CLASS_LIST);
2219 assert_eq!(
2220 JavaClass::Of("a.java.Class").get_class_str(),
2221 "a.java.Class"
2222 );
2223
2224 Ok(())
2225 }
2226
2227 #[test]
2228 fn test_byte_array_to_rust() -> errors::Result<()> {
2229 let jvm = create_tests_jvm()?;
2230 let rust_value: Vec<i8> = vec![-3_i8, 7_i8, 8_i8];
2231 let ia: Vec<_> = rust_value.iter().map(|x| InvocationArg::try_from(x).unwrap().into_primitive().unwrap()).collect();
2232 let java_instance = jvm.create_java_array(PRIMITIVE_BYTE, &ia)?;
2233 let rust_value_from_java: Vec<i8> = jvm.to_rust(java_instance)?;
2234 assert_eq!(rust_value_from_java, rust_value);
2235
2236 Ok(())
2237 }
2238
2239 #[test]
2240 fn test_short_array_to_rust() -> errors::Result<()> {
2241 let jvm = create_tests_jvm()?;
2242 let rust_value: Vec<i16> = vec![-3_i16, 7_i16, 10000_i16];
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_SHORT, &ia)?;
2245 let rust_value_from_java: Vec<i16> = jvm.to_rust(java_instance)?;
2246 assert_eq!(rust_value_from_java, rust_value);
2247
2248 Ok(())
2249 }
2250
2251 #[test]
2252 fn test_char_array_to_rust() -> errors::Result<()> {
2253 let jvm = create_tests_jvm()?;
2254 let rust_value: Vec<u16> = vec![3_u16, 7_u16, 10000_u16];
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_CHAR, &ia)?;
2257 let rust_value_from_java: Vec<u16> = jvm.to_rust(java_instance)?;
2258 assert_eq!(rust_value_from_java, rust_value);
2259
2260 Ok(())
2261 }
2262
2263 #[test]
2264 fn test_int_array_to_rust() -> errors::Result<()> {
2265 let jvm = create_tests_jvm()?;
2266 let rust_value: Vec<i32> = vec![-100_000, -1_000_000, 1_000_000];
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_INT, &ia)?;
2269 let rust_value_from_java: Vec<i32> = jvm.to_rust(java_instance)?;
2270 assert_eq!(rust_value_from_java, rust_value);
2271
2272 Ok(())
2273 }
2274
2275 #[test]
2276 fn test_long_array_to_rust() -> errors::Result<()> {
2277 let jvm = create_tests_jvm()?;
2278 let rust_value: Vec<i64> = 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_LONG, &ia)?;
2281 let rust_value_from_java: Vec<i64> = jvm.to_rust(java_instance)?;
2282 assert_eq!(rust_value_from_java, rust_value);
2283
2284 Ok(())
2285 }
2286
2287 #[test]
2288 fn test_float_array_to_rust() -> errors::Result<()> {
2289 let jvm = create_tests_jvm()?;
2290 let rust_value: Vec<f32> = vec![3_f32, 7.5_f32, -1000.5_f32];
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_FLOAT, &ia)?;
2293 let rust_value_from_java: Vec<f32> = jvm.to_rust(java_instance)?;
2294 assert_eq!(rust_value_from_java, rust_value);
2295
2296 Ok(())
2297 }
2298
2299 #[test]
2300 fn test_double_array_to_rust() -> errors::Result<()> {
2301 let jvm = create_tests_jvm()?;
2302 let rust_value: Vec<f64> = vec![3_f64, 7.5_f64, -1000.5_f64];
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_DOUBLE, &ia)?;
2305 let rust_value_from_java: Vec<f64> = jvm.to_rust(java_instance)?;
2306 assert_eq!(rust_value_from_java, rust_value);
2307
2308 Ok(())
2309 }
2310
2311 #[test]
2312 fn test_boolean_array_to_rust() -> errors::Result<()> {
2313 let jvm = create_tests_jvm()?;
2314 let rust_value: Vec<bool> = vec![false, true, false];
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_BOOLEAN, &ia)?;
2317 let rust_value_from_java: Vec<bool> = jvm.to_rust(java_instance)?;
2318 assert_eq!(rust_value_from_java, rust_value);
2319
2320 Ok(())
2321 }
2322
2323 #[test]
2324 fn test_int_to_rust() -> errors::Result<()> {
2325 let jvm = create_tests_jvm()?;
2326 let rust_value: i32 = 3;
2327 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2328 let java_instance = jvm.create_instance(CLASS_INTEGER, &[ia])?;
2329 let java_primitive_instance = jvm.invoke(&java_instance, "intValue", InvocationArg::empty())?;
2330 let rust_value_from_java: i32 = jvm.to_rust(java_instance)?;
2331 assert_eq!(rust_value_from_java, rust_value);
2332 let rust_value_from_java: i32 = jvm.to_rust(java_primitive_instance)?;
2333 assert_eq!(rust_value_from_java, rust_value);
2334
2335 Ok(())
2336 }
2337
2338 #[test]
2339 fn test_byte_to_rust() -> errors::Result<()> {
2340 let jvm = create_tests_jvm()?;
2341 let rust_value: i8 = 3;
2342 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2343 let java_instance = jvm.create_instance(CLASS_BYTE, &[ia])?;
2344 let java_primitive_instance = jvm.invoke(&java_instance, "byteValue", InvocationArg::empty())?;
2345 let rust_value_from_java: i8 = jvm.to_rust(java_instance)?;
2346 assert_eq!(rust_value_from_java, rust_value);
2347 let rust_value_from_java: i8 = jvm.to_rust(java_primitive_instance)?;
2348 assert_eq!(rust_value_from_java, rust_value);
2349
2350 Ok(())
2351 }
2352
2353 #[test]
2354 fn test_short_to_rust() -> errors::Result<()> {
2355 let jvm = create_tests_jvm()?;
2356 let rust_value: i16 = 3;
2357 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2358 let java_instance = jvm.create_instance(CLASS_SHORT, &[ia])?;
2359 let java_primitive_instance = jvm.invoke(&java_instance, "shortValue", InvocationArg::empty())?;
2360 let rust_value_from_java: i16 = jvm.to_rust(java_instance)?;
2361 assert_eq!(rust_value_from_java, rust_value);
2362 let rust_value_from_java: i16 = jvm.to_rust(java_primitive_instance)?;
2363 assert_eq!(rust_value_from_java, rust_value);
2364
2365 Ok(())
2366 }
2367
2368 #[test]
2369 fn test_char_to_rust() -> errors::Result<()> {
2370 let jvm = create_tests_jvm()?;
2371 let rust_value: u16 = 3;
2372 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2373 let java_instance = jvm.create_instance(CLASS_CHARACTER, &[ia])?;
2374 let java_primitive_instance = jvm.invoke(&java_instance, "charValue", InvocationArg::empty())?;
2375 let rust_value_from_java: u16 = jvm.to_rust(java_instance)?;
2376 assert_eq!(rust_value_from_java, rust_value);
2377 let rust_value_from_java: u16 = jvm.to_rust(java_primitive_instance)?;
2378 assert_eq!(rust_value_from_java, rust_value);
2379
2380 Ok(())
2381 }
2382
2383 #[test]
2384 fn test_long_to_rust() -> errors::Result<()> {
2385 let jvm = create_tests_jvm()?;
2386 let rust_value: i64 = 3;
2387 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2388 let java_instance = jvm.create_instance(CLASS_LONG, &[ia])?;
2389 let java_primitive_instance = jvm.invoke(&java_instance, "longValue", InvocationArg::empty())?;
2390 let rust_value_from_java: i64 = jvm.to_rust(java_instance)?;
2391 assert_eq!(rust_value_from_java, rust_value);
2392 let rust_value_from_java: i64 = jvm.to_rust(java_primitive_instance)?;
2393 assert_eq!(rust_value_from_java, rust_value);
2394
2395 Ok(())
2396 }
2397
2398 #[test]
2399 fn test_float_to_rust() -> errors::Result<()> {
2400 let jvm = create_tests_jvm()?;
2401 let rust_value: f32 = 3.3;
2402 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2403 let java_instance = jvm.create_instance(CLASS_FLOAT, &[ia])?;
2404 let java_primitive_instance = jvm.invoke(&java_instance, "floatValue", InvocationArg::empty())?;
2405 let rust_value_from_java: f32 = jvm.to_rust(java_instance)?;
2406 assert_eq!(rust_value_from_java, rust_value);
2407 let rust_value_from_java: f32 = jvm.to_rust(java_primitive_instance)?;
2408 assert_eq!(rust_value_from_java, rust_value);
2409
2410 Ok(())
2411 }
2412
2413 #[test]
2414 fn test_double_to_rust() -> errors::Result<()> {
2415 let jvm = create_tests_jvm()?;
2416 let rust_value: f64 = 3.3;
2417 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2418 let java_instance = jvm.create_instance(CLASS_DOUBLE, &[ia])?;
2419 let java_primitive_instance = jvm.invoke(&java_instance, "doubleValue", InvocationArg::empty())?;
2420 let rust_value_from_java: f64 = jvm.to_rust(java_instance)?;
2421 assert_eq!(rust_value_from_java, rust_value);
2422 let rust_value_from_java: f64 = jvm.to_rust(java_primitive_instance)?;
2423 assert_eq!(rust_value_from_java, rust_value);
2424
2425 Ok(())
2426 }
2427
2428 #[test]
2429 fn api_by_ref_or_value() -> errors::Result<()> {
2430 let jvm = create_tests_jvm()?;
2431
2432 let inv_arg1 = InvocationArg::try_from("some string")?;
2434 let _ = jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", &[&inv_arg1])?;
2435 let _ = jvm.create_instance("java.lang.String", &[inv_arg1])?;
2436 Ok(())
2437 }
2438
2439 #[test]
2440 fn exception_string_in_the_result() -> errors::Result<()> {
2441 let jvm = create_tests_jvm()?;
2442
2443 let res = jvm.create_instance("non.Existing", InvocationArg::empty());
2444 assert!(res.is_err());
2445 let exception_sttring = format!("{}",res.err().unwrap());
2446 assert!(exception_sttring.contains("Cannot create instance of non.Existing"));
2447
2448 Ok(())
2449 }
2450}