1use std::any::{Any, TypeId};
16use std::borrow::Borrow;
17use std::collections::HashMap;
18use std::convert::TryFrom;
19use std::env;
20use std::ops::Drop;
21use std::os::raw::c_void;
22use std::path::{Path, PathBuf};
23use std::ptr;
24use std::sync::mpsc::channel;
25use std::{fs, thread, time};
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::{opt_to_res, J4RsError};
38use crate::jni_utils;
39use crate::provisioning;
40use crate::provisioning::{get_maven_settings, JavaArtifact, LocalJarArtifact, MavenArtifact};
41use crate::utils;
42use crate::{api_tweaks as tweaks, cache, InvocationArg, MavenSettings};
43use crate::{errors, set_java_vm};
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 = "org.astonbitecode.j4rs.api.jfx.J4rsFxmlLoader";
88pub const _JNI_VERSION_10: jint = 0x000a0000;
89
90pub type Callback = fn(Jvm, Instance) -> ();
91
92#[derive(Clone)]
94pub struct Jvm {
95 pub(crate) jni_env: *mut JNIEnv,
96 detach_thread_on_drop: bool,
97}
98
99impl Jvm {
100 pub fn new(jvm_options: &[String], lib_name_to_load: Option<String>) -> errors::Result<Jvm> {
102 Self::create_jvm(jvm_options, lib_name_to_load)
103 }
104
105 pub fn attach_thread() -> errors::Result<Jvm> {
107 Self::create_jvm(&[], None)
108 }
109
110 pub fn attach_thread_with_no_detach_on_drop() -> errors::Result<Jvm> {
116 let mut jvm = Jvm::attach_thread()?;
117 jvm.detach_thread_on_drop(false);
118 Ok(jvm)
119 }
120
121 pub fn detach_thread_on_drop(&mut self, detach: bool) {
127 self.detach_thread_on_drop = detach;
128 }
129
130 fn create_jvm(jvm_options: &[String], lib_name_to_load: Option<String>) -> errors::Result<Jvm> {
133 debug("Creating a Jvm");
134 let mut jvm: *mut JavaVM = ptr::null_mut();
135 let mut jni_environment: *mut JNIEnv = ptr::null_mut();
136
137 let _g = cache::MUTEX.lock()?;
139
140 let result = if let Some(env) = cache::get_thread_local_env_opt() {
141 debug("A JVM is already created for this thread. Retrieving it...");
142 jni_environment = env;
143
144 JNI_OK
145 } else {
146 let created_vm = Self::get_created_vm();
147
148 let res_int = if created_vm.is_some() {
149 debug("A JVM is already created by another thread. Retrieving it...");
150 jni_environment = created_vm.unwrap();
151
152 JNI_OK
153 } else {
154 info("No JVMs exist. Creating a new one...");
155 let mut cstrings_to_drop: Vec<*mut c_char> = Vec::with_capacity(jvm_options.len());
156 let mut jvm_options_vec: Vec<JavaVMOption> = jvm_options
157 .iter()
158 .map(|opt| {
159 let cstr = utils::to_c_string(opt);
160 let jo = JavaVMOption {
161 optionString: cstr,
162 extraInfo: ptr::null_mut() as *mut c_void,
163 };
164 cstrings_to_drop.push(cstr);
165 jo
166 })
167 .collect();
168
169 let mut jvm_arguments = JavaVMInitArgs {
170 version: JNI_VERSION_1_6,
171 nOptions: jvm_options.len() as i32,
172 options: jvm_options_vec.as_mut_ptr(),
173 ignoreUnrecognized: JNI_TRUE,
174 };
175
176 let int_result = tweaks::create_java_vm(
177 &mut jvm,
178 (&mut jni_environment as *mut *mut JNIEnv) as *mut *mut c_void,
179 (&mut jvm_arguments as *mut JavaVMInitArgs) as *mut c_void,
180 );
181
182 cstrings_to_drop
183 .into_iter()
184 .for_each(|s| unsafe { utils::drop_c_string(s) });
185
186 int_result
187 };
188
189 res_int
190 };
191
192 if result != JNI_OK {
193 let error_message = match result {
194 JNI_EDETACHED => "thread detached from the JVM",
195 JNI_EEXIST => "JVM already created",
196 JNI_EINVAL => "invalid arguments",
197 JNI_ENOMEM => "not enough memory",
198 JNI_ERR => "unknown error",
199 JNI_EVERSION => "JNI version error",
200 _ => "unknown JNI error value",
201 };
202
203 Err(J4RsError::JavaError(
204 format!("Could not create the JVM: {}", error_message).to_string(),
205 ))
206 } else {
207 let jvm = unsafe { Self::try_from(jni_environment)? };
208 if let Some(libname) = lib_name_to_load {
209 debug(&format!(
211 "Initializing NativeCallbackSupport with libname {}",
212 libname
213 ));
214 jvm.invoke_static(
215 CLASS_NATIVE_CALLBACK_TO_RUST_CHANNEL_SUPPORT,
216 "initialize",
217 &[InvocationArg::try_from(libname)?],
218 )?;
219 debug("NativeCallbackSupport initialized");
220 }
221
222 Ok(jvm)
223 }
224 }
225
226 pub unsafe fn try_from(jni_environment: *mut JNIEnv) -> errors::Result<Jvm> {
227 if cache::get_thread_local_env_opt().is_none() {
228 let _ = cache::get_jni_get_method_id().or_else(|| {
230 cache::set_jni_get_method_id(Some((**jni_environment).v1_6.GetMethodID))
231 });
232 let _ = cache::get_jni_get_static_method_id().or_else(|| {
233 cache::set_jni_get_static_method_id(Some(
234 (**jni_environment).v1_6.GetStaticMethodID,
235 ))
236 });
237 let _ = cache::get_jni_new_object()
238 .or_else(|| cache::set_jni_new_object(Some((**jni_environment).v1_6.NewObject)));
239 let _ = cache::get_jni_new_string_utf().or_else(|| {
240 cache::set_jni_new_string_utf(Some((**jni_environment).v1_6.NewStringUTF))
241 });
242 let _ = cache::get_jni_get_string_utf_chars().or_else(|| {
243 cache::set_jni_get_string_utf_chars(Some(
244 (**jni_environment).v1_6.GetStringUTFChars,
245 ))
246 });
247 let _ = cache::get_jni_release_string_utf_chars().or_else(|| {
248 cache::set_jni_release_string_utf_chars(Some(
249 (**jni_environment).v1_6.ReleaseStringUTFChars,
250 ))
251 });
252 let _ = cache::get_jni_call_object_method().or_else(|| {
253 cache::set_jni_call_object_method(Some((**jni_environment).v1_6.CallObjectMethod))
254 });
255 let _ = cache::get_jni_call_boolean_method().or_else(|| {
256 cache::set_jni_call_boolean_method(Some((**jni_environment).v1_6.CallBooleanMethod))
257 });
258 let _ = cache::get_jni_call_byte_method().or_else(|| {
259 cache::set_jni_call_byte_method(Some((**jni_environment).v1_6.CallByteMethod))
260 });
261 let _ = cache::get_jni_call_short_method().or_else(|| {
262 cache::set_jni_call_short_method(Some((**jni_environment).v1_6.CallShortMethod))
263 });
264 let _ = cache::get_jni_call_char_method().or_else(|| {
265 cache::set_jni_call_char_method(Some((**jni_environment).v1_6.CallCharMethod))
266 });
267 let _ = cache::get_jni_call_int_method().or_else(|| {
268 cache::set_jni_call_int_method(Some((**jni_environment).v1_6.CallIntMethod))
269 });
270 let _ = cache::get_jni_call_long_method().or_else(|| {
271 cache::set_jni_call_long_method(Some((**jni_environment).v1_6.CallLongMethod))
272 });
273 let _ = cache::get_jni_call_float_method().or_else(|| {
274 cache::set_jni_call_float_method(Some((**jni_environment).v1_6.CallFloatMethod))
275 });
276 let _ = cache::get_jni_call_double_method().or_else(|| {
277 cache::set_jni_call_double_method(Some((**jni_environment).v1_6.CallDoubleMethod))
278 });
279 let _ = cache::get_jni_call_void_method().or_else(|| {
280 cache::set_jni_call_void_method(Some((**jni_environment).v1_6.CallVoidMethod))
281 });
282 let _ = cache::get_jni_call_static_object_method().or_else(|| {
283 cache::set_jni_call_static_object_method(Some(
284 (**jni_environment).v1_6.CallStaticObjectMethod,
285 ))
286 });
287 let _ = cache::get_jni_get_array_length().or_else(|| {
288 cache::set_jni_get_array_length(Some((**jni_environment).v1_6.GetArrayLength))
289 });
290 let _ = cache::get_jni_get_byte_array_elements().or_else(|| {
291 cache::set_jni_get_byte_array_elements(Some(
292 (**jni_environment).v1_6.GetByteArrayElements,
293 ))
294 });
295 let _ = cache::get_jni_release_byte_array_elements().or_else(|| {
296 cache::set_jni_release_byte_array_elements(Some(
297 (**jni_environment).v1_6.ReleaseByteArrayElements,
298 ))
299 });
300 let _ = cache::get_jni_get_short_array_elements().or_else(|| {
301 cache::set_jni_get_short_array_elements(Some(
302 (**jni_environment).v1_6.GetShortArrayElements,
303 ))
304 });
305 let _ = cache::get_jni_release_short_array_elements().or_else(|| {
306 cache::set_jni_release_short_array_elements(Some(
307 (**jni_environment).v1_6.ReleaseShortArrayElements,
308 ))
309 });
310 let _ = cache::get_jni_get_char_array_elements().or_else(|| {
311 cache::set_jni_get_char_array_elements(Some(
312 (**jni_environment).v1_6.GetCharArrayElements,
313 ))
314 });
315 let _ = cache::get_jni_release_char_array_elements().or_else(|| {
316 cache::set_jni_release_char_array_elements(Some(
317 (**jni_environment).v1_6.ReleaseCharArrayElements,
318 ))
319 });
320 let _ = cache::get_jni_get_int_array_elements().or_else(|| {
321 cache::set_jni_get_int_array_elements(Some(
322 (**jni_environment).v1_6.GetIntArrayElements,
323 ))
324 });
325 let _ = cache::get_jni_release_int_array_elements().or_else(|| {
326 cache::set_jni_release_int_array_elements(Some(
327 (**jni_environment).v1_6.ReleaseIntArrayElements,
328 ))
329 });
330 let _ = cache::get_jni_get_long_array_elements().or_else(|| {
331 cache::set_jni_get_long_array_elements(Some(
332 (**jni_environment).v1_6.GetLongArrayElements,
333 ))
334 });
335 let _ = cache::get_jni_release_long_array_elements().or_else(|| {
336 cache::set_jni_release_long_array_elements(Some(
337 (**jni_environment).v1_6.ReleaseLongArrayElements,
338 ))
339 });
340 let _ = cache::get_jni_get_float_array_elements().or_else(|| {
341 cache::set_jni_get_float_array_elements(Some(
342 (**jni_environment).v1_6.GetFloatArrayElements,
343 ))
344 });
345 let _ = cache::get_jni_release_float_array_elements().or_else(|| {
346 cache::set_jni_release_float_array_elements(Some(
347 (**jni_environment).v1_6.ReleaseFloatArrayElements,
348 ))
349 });
350 let _ = cache::get_jni_get_double_array_elements().or_else(|| {
351 cache::set_jni_get_double_array_elements(Some(
352 (**jni_environment).v1_6.GetDoubleArrayElements,
353 ))
354 });
355 let _ = cache::get_jni_release_double_array_elements().or_else(|| {
356 cache::set_jni_release_double_array_elements(Some(
357 (**jni_environment).v1_6.ReleaseDoubleArrayElements,
358 ))
359 });
360 let _ = cache::get_jni_get_boolean_array_elements().or_else(|| {
361 cache::set_jni_get_boolean_array_elements(Some(
362 (**jni_environment).v1_6.GetBooleanArrayElements,
363 ))
364 });
365 let _ = cache::get_jni_release_boolean_array_elements().or_else(|| {
366 cache::set_jni_release_boolean_array_elements(Some(
367 (**jni_environment).v1_6.ReleaseBooleanArrayElements,
368 ))
369 });
370 let _ = cache::get_jni_new_object_array().or_else(|| {
371 cache::set_jni_new_object_array(Some((**jni_environment).v1_6.NewObjectArray))
372 });
373 let _ = cache::get_jni_set_object_array_element().or_else(|| {
374 cache::set_jni_set_object_array_element(Some(
375 (**jni_environment).v1_6.SetObjectArrayElement,
376 ))
377 });
378 let ec = cache::get_jni_exception_check().or_else(|| {
379 cache::set_jni_exception_check(Some((**jni_environment).v1_6.ExceptionCheck))
380 });
381 let ed = cache::get_jni_exception_describe().or_else(|| {
382 cache::set_jni_exception_describe(Some((**jni_environment).v1_6.ExceptionDescribe))
383 });
384 let _ = cache::get_jni_exception_occured().or_else(|| {
385 cache::set_jni_exception_occured(Some((**jni_environment).v1_6.ExceptionOccurred))
386 });
387 let exclear = cache::get_jni_exception_clear().or_else(|| {
388 cache::set_jni_exception_clear(Some((**jni_environment).v1_6.ExceptionClear))
389 });
390 let _ = cache::get_jni_delete_local_ref().or_else(|| {
391 cache::set_jni_delete_local_ref(Some((**jni_environment).v1_6.DeleteLocalRef))
392 });
393 let _ = cache::get_jni_delete_global_ref().or_else(|| {
394 cache::set_jni_delete_global_ref(Some((**jni_environment).v1_6.DeleteGlobalRef))
395 });
396 let _ = cache::get_jni_new_global_ref().or_else(|| {
397 cache::set_jni_new_global_ref(Some((**jni_environment).v1_6.NewGlobalRef))
398 });
399 let _ = cache::get_jni_throw_new()
400 .or_else(|| cache::set_jni_throw_new(Some((**jni_environment).v1_6.ThrowNew)));
401 let _ = cache::get_is_same_object()
402 .or_else(|| cache::set_is_same_object(Some((**jni_environment).v1_6.IsSameObject)));
403
404 match (ec, ed, exclear) {
405 (Some(ec), Some(ed), Some(exclear)) => {
406 if (ec)(jni_environment) == JNI_TRUE {
407 (ed)(jni_environment);
408 (exclear)(jni_environment);
409 Err(J4RsError::JavaError(
410 "The VM cannot be started... Please check the logs.".to_string(),
411 ))
412 } else {
413 let jvm = Jvm {
414 jni_env: jni_environment,
415 detach_thread_on_drop: true,
416 };
417
418 cache::set_thread_local_env(Some(jni_environment));
419 cache::add_active_jvm();
420
421 Ok(jvm)
422 }
423 }
424 (_, _, _) => Err(J4RsError::JniError(
425 "Could not initialize the JVM: Error while trying to retrieve JNI functions."
426 .to_string(),
427 )),
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 = inv_args[i as usize]
476 .borrow()
477 .as_java_ptr_with_global_ref(self.jni_env)?;
478 (opt_to_res(cache::get_jni_set_object_array_element())?)(
480 self.jni_env,
481 array_ptr,
482 i,
483 inv_arg_java,
484 );
485 inv_arg_jobjects.push(inv_arg_java);
486 }
487 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
490 self.jni_env,
491 cache::get_factory_class()?,
492 cache::get_factory_instantiate_method()?,
493 class_name_jstring,
494 array_ptr,
495 );
496
497 Self::do_return(self.jni_env, ())?;
499
500 let java_instance_global_instance =
501 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
502 jni_utils::delete_java_ref(self.jni_env, array_ptr);
504 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
505 for inv_arg_jobject in inv_arg_jobjects {
506 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
507 }
508
509 Self::do_return(
511 self.jni_env,
512 Instance {
513 jinstance: java_instance_global_instance,
514 class_name: class_name.to_string(),
515 skip_deleting_jobject: false,
516 },
517 )
518 }
519 }
520
521 pub fn static_class(&self, class_name: &str) -> errors::Result<Instance> {
523 debug(&format!("Retrieving static class {}", class_name));
524 unsafe {
525 let class_name_jstring: jstring =
527 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
528
529 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
532 self.jni_env,
533 cache::get_factory_class()?,
534 cache::get_factory_create_for_static_method()?,
535 class_name_jstring,
536 );
537
538 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
539
540 Self::do_return(
542 self.jni_env,
543 Instance::from_jobject_with_global_ref(java_instance)?,
544 )
545 }
546 }
547
548 pub fn create_java_array(
552 &self,
553 class_name: &str,
554 inv_args: &[impl Borrow<InvocationArg>],
555 ) -> errors::Result<Instance> {
556 debug(&format!(
557 "Creating a java array of class {} with {} elements",
558 class_name,
559 inv_args.len()
560 ));
561 unsafe {
562 let class_name_jstring: jstring =
564 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
565
566 let size = inv_args.len() as i32;
568 let array_ptr = {
569 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
570 self.jni_env,
571 size,
572 cache::get_invocation_arg_class()?,
573 ptr::null_mut(),
574 );
575 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
576 };
577 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
578
579 for i in 0..size {
581 let inv_arg_java = inv_args[i as usize]
583 .borrow()
584 .as_java_ptr_with_global_ref(self.jni_env)?;
585 (opt_to_res(cache::get_jni_set_object_array_element())?)(
587 self.jni_env,
588 array_ptr,
589 i,
590 inv_arg_java,
591 );
592 inv_arg_jobjects.push(inv_arg_java);
593 }
594 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
597 self.jni_env,
598 cache::get_factory_class()?,
599 cache::get_factory_create_java_array_method()?,
600 class_name_jstring,
601 array_ptr,
602 );
603
604 Self::do_return(self.jni_env, ())?;
606
607 let java_instance_global_instance =
608 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
609 for inv_arg_jobject in inv_arg_jobjects {
611 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
612 }
613 jni_utils::delete_java_ref(self.jni_env, array_ptr);
614 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
615
616 Self::do_return(
618 self.jni_env,
619 Instance {
620 jinstance: java_instance_global_instance,
621 class_name: class_name.to_string(),
622 skip_deleting_jobject: false,
623 },
624 )
625 }
626 }
627
628 pub fn java_list<'a>(
630 &self,
631 inner_class_name: impl Into<&'a str>,
632 inv_args: Vec<impl TryInto<InvocationArg, Error = J4RsError>>,
633 ) -> errors::Result<Instance> {
634 let v: Result<Vec<InvocationArg>, J4RsError> =
635 inv_args.into_iter().map(|arg| arg.try_into()).collect();
636 Self::do_create_java_list(self.jni_env, inner_class_name.into(), v?.as_ref())
637 }
638
639 fn do_create_java_list(
640 jni_env: *mut JNIEnv,
641 class_name: &str,
642 inv_args: &[InvocationArg],
643 ) -> errors::Result<Instance> {
644 debug(&format!(
645 "Creating a java list of class {} with {} elements",
646 class_name,
647 inv_args.len()
648 ));
649 unsafe {
650 let class_name_jstring: jstring =
652 jni_utils::global_jobject_from_str(class_name, jni_env)?;
653
654 let size = inv_args.len() as i32;
656 let array_ptr = {
657 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
658 jni_env,
659 size,
660 cache::get_invocation_arg_class()?,
661 ptr::null_mut(),
662 );
663 jni_utils::create_global_ref_from_local_ref(j, jni_env)?
664 };
665 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
666
667 for i in 0..size {
669 let inv_arg_java = inv_args[i as usize].as_java_ptr_with_global_ref(jni_env)?;
671 (opt_to_res(cache::get_jni_set_object_array_element())?)(
673 jni_env,
674 array_ptr,
675 i,
676 inv_arg_java,
677 );
678 inv_arg_jobjects.push(inv_arg_java);
679 }
680 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
683 jni_env,
684 cache::get_factory_class()?,
685 cache::get_factory_create_java_list_method()?,
686 class_name_jstring,
687 array_ptr,
688 );
689
690 Self::do_return(jni_env, ())?;
692
693 let java_instance_global_instance =
694 jni_utils::create_global_ref_from_local_ref(java_instance, jni_env)?;
695 for inv_arg_jobject in inv_arg_jobjects {
697 jni_utils::delete_java_ref(jni_env, inv_arg_jobject);
698 }
699 jni_utils::delete_java_ref(jni_env, array_ptr);
700 jni_utils::delete_java_ref(jni_env, class_name_jstring);
701
702 Self::do_return(
704 jni_env,
705 Instance {
706 jinstance: java_instance_global_instance,
707 class_name: class_name.to_string(),
708 skip_deleting_jobject: false,
709 },
710 )
711 }
712 }
713
714 pub fn java_map<'a>(
716 &self,
717 key_class_name: impl Into<&'a str>,
718 value_class_name: impl Into<&'a str>,
719 inv_args: HashMap<
720 impl TryInto<InvocationArg, Error = J4RsError>,
721 impl TryInto<InvocationArg, Error = J4RsError>,
722 >,
723 ) -> errors::Result<Instance> {
724 let mut inv_args_results: Vec<Result<InvocationArg, J4RsError>> =
725 Vec::with_capacity(inv_args.len() * 2);
726 let mut i = 0;
727 let mut inv_args = inv_args;
728
729 for (key, val) in inv_args.drain() {
730 inv_args_results.insert(i, key.try_into());
731 i += 1;
732 inv_args_results.insert(i, val.try_into());
733 i += 1;
734 }
735 let inv_args: Result<Vec<InvocationArg>, J4RsError> = inv_args_results
736 .into_iter()
737 .map(|arg| arg.try_into())
738 .collect();
739 Self::do_create_java_map(
740 self.jni_env,
741 key_class_name.into(),
742 value_class_name.into(),
743 inv_args?.as_ref(),
744 )
745 }
746
747 fn do_create_java_map(
748 jni_env: *mut JNIEnv,
749 key_class_name: &str,
750 value_class_name: &str,
751 inv_args: &[InvocationArg],
752 ) -> errors::Result<Instance> {
753 debug(&format!(
754 "Creating a java map with keys of class {} and values of class {} with {} elements",
755 key_class_name,
756 value_class_name,
757 inv_args.len() / 2
758 ));
759 unsafe {
760 let key_class_name_jstring: jstring =
762 jni_utils::global_jobject_from_str(key_class_name, jni_env)?;
763 let value_class_name_jstring: jstring =
765 jni_utils::global_jobject_from_str(value_class_name, jni_env)?;
766
767 let size = inv_args.len() as i32;
769 let array_ptr = {
770 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
771 jni_env,
772 size,
773 cache::get_invocation_arg_class()?,
774 ptr::null_mut(),
775 );
776 jni_utils::create_global_ref_from_local_ref(j, jni_env)?
777 };
778 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
779
780 for i in 0..size {
782 let inv_arg_java = inv_args[i as usize].as_java_ptr_with_global_ref(jni_env)?;
784 (opt_to_res(cache::get_jni_set_object_array_element())?)(
786 jni_env,
787 array_ptr,
788 i,
789 inv_arg_java,
790 );
791 inv_arg_jobjects.push(inv_arg_java);
792 }
793 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
797 jni_env,
798 cache::get_factory_class()?,
799 cache::get_factory_create_java_map_method()?,
800 key_class_name_jstring,
801 value_class_name_jstring,
802 array_ptr,
803 );
804
805 Self::do_return(jni_env, ())?;
807
808 let java_instance_global_instance =
809 jni_utils::create_global_ref_from_local_ref(java_instance, jni_env)?;
810 for inv_arg_jobject in inv_arg_jobjects {
812 jni_utils::delete_java_ref(jni_env, inv_arg_jobject);
813 }
814 jni_utils::delete_java_ref(jni_env, array_ptr);
815 jni_utils::delete_java_ref(jni_env, value_class_name_jstring);
816 jni_utils::delete_java_ref(jni_env, key_class_name_jstring);
817
818 Self::do_return(
820 jni_env,
821 Instance {
822 jinstance: java_instance_global_instance,
823 class_name: "".to_string(),
824 skip_deleting_jobject: false,
825 },
826 )
827 }
828 }
829
830 pub fn invoke(
832 &self,
833 instance: &Instance,
834 method_name: &str,
835 inv_args: &[impl Borrow<InvocationArg>],
836 ) -> errors::Result<Instance> {
837 debug(&format!(
838 "Invoking method {} of class {} using {} arguments",
839 method_name,
840 instance.class_name,
841 inv_args.len()
842 ));
843 unsafe {
844 let method_name_jstring: jstring =
846 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
847
848 let size = inv_args.len() as i32;
850 let array_ptr = {
851 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
852 self.jni_env,
853 size,
854 cache::get_invocation_arg_class()?,
855 ptr::null_mut(),
856 );
857 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
858 };
859 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
860
861 for i in 0..size {
863 let inv_arg_java = inv_args[i as usize]
865 .borrow()
866 .as_java_ptr_with_global_ref(self.jni_env)?;
867 (opt_to_res(cache::get_jni_set_object_array_element())?)(
869 self.jni_env,
870 array_ptr,
871 i,
872 inv_arg_java,
873 );
874 inv_arg_jobjects.push(inv_arg_java);
875 }
876
877 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
879 self.jni_env,
880 instance.jinstance,
881 cache::get_invoke_method()?,
882 method_name_jstring,
883 array_ptr,
884 );
885
886 Self::do_return(self.jni_env, ())?;
888
889 let java_instance_global_instance =
890 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
891 for inv_arg_jobject in inv_arg_jobjects {
893 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
894 }
895 jni_utils::delete_java_ref(self.jni_env, array_ptr);
896 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
897
898 Self::do_return(
900 self.jni_env,
901 Instance {
902 jinstance: java_instance_global_instance,
903 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
904 skip_deleting_jobject: false,
905 },
906 )
907 }
908 }
909
910 pub fn field(&self, instance: &Instance, field_name: &str) -> errors::Result<Instance> {
912 debug(&format!(
913 "Retrieving field {} of class {}",
914 field_name, instance.class_name
915 ));
916 unsafe {
917 let field_name_jstring: jstring =
919 jni_utils::global_jobject_from_str(field_name, self.jni_env)?;
920
921 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
923 self.jni_env,
924 instance.jinstance,
925 cache::get_field_method()?,
926 field_name_jstring,
927 );
928
929 Self::do_return(self.jni_env, ())?;
931
932 let java_instance_global_instance =
933 jni_utils::create_global_ref_from_local_ref(java_instance, self.jni_env)?;
934 jni_utils::delete_java_ref(self.jni_env, field_name_jstring);
936
937 Self::do_return(
939 self.jni_env,
940 Instance {
941 jinstance: java_instance_global_instance,
942 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
943 skip_deleting_jobject: false,
944 },
945 )
946 }
947 }
948
949 pub fn static_class_field(
951 &self,
952 class_name: &str,
953 field_name: &str,
954 ) -> errors::Result<Instance> {
955 debug(&format!(
956 "Retrieving field {} of static class {}",
957 field_name, class_name
958 ));
959 let i = self.static_class(class_name)?;
960 self.field(&i, field_name)
961 }
962
963 pub fn invoke_to_channel(
966 &self,
967 instance: &Instance,
968 method_name: &str,
969 inv_args: &[impl Borrow<InvocationArg>],
970 ) -> errors::Result<InstanceReceiver> {
971 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()));
972 unsafe {
973 let (sender, rx) = channel();
975 let tx = Box::new(sender);
976 let raw_ptr = Box::into_raw(tx);
978 let address_string = format!("{:p}", raw_ptr);
980 let address = u64::from_str_radix(&address_string[2..], 16).unwrap();
981
982 let method_name_jstring: jstring =
984 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
985
986 let size = inv_args.len() as i32;
988 let array_ptr = {
989 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
990 self.jni_env,
991 size,
992 cache::get_invocation_arg_class()?,
993 ptr::null_mut(),
994 );
995 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
996 };
997 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
998
999 for i in 0..size {
1001 let inv_arg_java = inv_args[i as usize]
1003 .borrow()
1004 .as_java_ptr_with_global_ref(self.jni_env)?;
1005 (opt_to_res(cache::get_jni_set_object_array_element())?)(
1007 self.jni_env,
1008 array_ptr,
1009 i,
1010 inv_arg_java,
1011 );
1012 inv_arg_jobjects.push(inv_arg_java);
1013 }
1014
1015 (opt_to_res(cache::get_jni_call_void_method())?)(
1017 self.jni_env,
1018 instance.jinstance,
1019 cache::get_invoke_to_channel_method()?,
1020 address,
1021 method_name_jstring,
1022 array_ptr,
1023 );
1024
1025 Self::do_return(self.jni_env, ())?;
1027
1028 for inv_arg_jobject in inv_arg_jobjects {
1030 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
1031 }
1032 jni_utils::delete_java_ref(self.jni_env, array_ptr);
1033 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
1034
1035 Self::do_return(self.jni_env, InstanceReceiver::new(rx, address))
1037 }
1038 }
1039
1040 pub fn init_callback_channel(&self, instance: &Instance) -> errors::Result<InstanceReceiver> {
1044 debug("Initializing callback channel");
1045 unsafe {
1046 let (sender, rx) = channel();
1048 let tx = Box::new(sender);
1049 let raw_ptr = Box::into_raw(tx);
1051 let address_string = format!("{:p}", raw_ptr);
1053 let address = u64::from_str_radix(&address_string[2..], 16).unwrap();
1054
1055 (opt_to_res(cache::get_jni_call_void_method())?)(
1057 self.jni_env,
1058 instance.jinstance,
1059 cache::get_init_callback_channel_method()?,
1060 address,
1061 );
1062
1063 Self::do_return(self.jni_env, InstanceReceiver::new(rx, address))
1065 }
1066 }
1067
1068 pub fn invoke_static(
1070 &self,
1071 class_name: &str,
1072 method_name: &str,
1073 inv_args: &[impl Borrow<InvocationArg>],
1074 ) -> errors::Result<Instance> {
1075 debug(&format!(
1076 "Invoking static method {} of class {} using {} arguments",
1077 method_name,
1078 class_name,
1079 inv_args.len()
1080 ));
1081 unsafe {
1082 let class_name_jstring: jstring =
1084 jni_utils::global_jobject_from_str(class_name, self.jni_env)?;
1085 let tmp_java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1088 self.jni_env,
1089 cache::get_factory_class()?,
1090 cache::get_factory_create_for_static_method()?,
1091 class_name_jstring,
1092 );
1093
1094 let method_name_jstring: jstring =
1096 jni_utils::global_jobject_from_str(method_name, self.jni_env)?;
1097
1098 let size = inv_args.len() as i32;
1100 let array_ptr = {
1101 let j = (opt_to_res(cache::get_jni_new_object_array())?)(
1102 self.jni_env,
1103 size,
1104 cache::get_invocation_arg_class()?,
1105 ptr::null_mut(),
1106 );
1107 jni_utils::create_global_ref_from_local_ref(j, self.jni_env)?
1108 };
1109 let mut inv_arg_jobjects: Vec<jobject> = Vec::with_capacity(size as usize);
1110 for i in 0..size {
1112 let inv_arg_java = inv_args[i as usize]
1114 .borrow()
1115 .as_java_ptr_with_global_ref(self.jni_env)?;
1116 (opt_to_res(cache::get_jni_set_object_array_element())?)(
1118 self.jni_env,
1119 array_ptr,
1120 i,
1121 inv_arg_java,
1122 );
1123 inv_arg_jobjects.push(inv_arg_java);
1124 }
1125 let java_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1127 self.jni_env,
1128 tmp_java_instance,
1129 cache::get_invoke_static_method()?,
1130 method_name_jstring,
1131 array_ptr,
1132 );
1133 jni_utils::delete_java_local_ref(self.jni_env, tmp_java_instance);
1135 jni_utils::delete_java_ref(self.jni_env, class_name_jstring);
1136 Self::do_return(self.jni_env, ())?;
1138
1139 for inv_arg_jobject in inv_arg_jobjects {
1141 jni_utils::delete_java_ref(self.jni_env, inv_arg_jobject);
1142 }
1143 jni_utils::delete_java_ref(self.jni_env, array_ptr);
1144 jni_utils::delete_java_ref(self.jni_env, method_name_jstring);
1145
1146 Self::do_return(
1148 self.jni_env,
1149 Instance::from_jobject_with_global_ref(java_instance)?,
1150 )
1151 }
1152 }
1153
1154 pub fn clone_instance(&self, instance: &Instance) -> errors::Result<Instance> {
1156 unsafe {
1157 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1159 self.jni_env,
1160 cache::get_class_to_invoke_clone_and_cast()?,
1161 cache::get_clone_static_method()?,
1162 instance.jinstance,
1163 );
1164
1165 Self::do_return(
1167 self.jni_env,
1168 Instance::from_jobject_with_global_ref(java_instance)?,
1169 )
1170 }
1171 }
1172
1173 pub fn cast(&self, from_instance: &Instance, to_class: &str) -> errors::Result<Instance> {
1175 debug(&format!("Casting to class {}", to_class));
1176 unsafe {
1177 let to_class_jstring: jstring =
1180 jni_utils::global_jobject_from_str(to_class, self.jni_env)?;
1181
1182 let java_instance = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1184 self.jni_env,
1185 cache::get_class_to_invoke_clone_and_cast()?,
1186 cache::get_cast_static_method()?,
1187 from_instance.jinstance,
1188 to_class_jstring,
1189 );
1190
1191 Self::do_return(self.jni_env, ())?;
1193
1194 jni_utils::delete_java_ref(self.jni_env, to_class_jstring);
1196
1197 Self::do_return(
1199 self.jni_env,
1200 Instance::from_jobject_with_global_ref(java_instance)?,
1201 )
1202 }
1203 }
1204
1205 pub fn check_equals(
1210 &self,
1211 instance: impl Borrow<Instance>,
1212 inv_arg: impl Borrow<InvocationArg>,
1213 ) -> errors::Result<bool> {
1214 debug(&format!(
1215 "Checking equality between instances of {} and {}",
1216 instance.borrow().class_name(),
1217 inv_arg.borrow().class_name()
1218 ));
1219 unsafe {
1220 let inv_arg_java_b = inv_arg.borrow().as_java_ptr_with_global_ref(self.jni_env)?;
1222 let java_boolean = (opt_to_res(cache::get_jni_call_boolean_method())?)(
1224 self.jni_env,
1225 instance.borrow().jinstance,
1226 cache::get_check_equals_method()?,
1227 inv_arg_java_b,
1228 );
1229
1230 Self::do_return(self.jni_env, java_boolean)
1232 }
1233 }
1234
1235 pub fn instance_into_raw_object(&self, instance: Instance) -> errors::Result<jobject> {
1237 debug(&format!(
1238 "Getting the raw jobject from instance of class {}",
1239 instance.borrow().class_name()
1240 ));
1241 let object_instance = unsafe {
1243 (opt_to_res(cache::get_jni_call_object_method())?)(
1244 self.jni_env,
1245 instance.jinstance,
1246 cache::get_get_object_method()?,
1247 )
1248 };
1249
1250 Self::do_return(self.jni_env, object_instance)
1251 }
1252
1253 pub fn into_raw(self) -> *mut JNIEnv {
1255 debug("Getting the raw JNIEnv from the Jvm");
1256
1257 self.jni_env
1258 }
1259
1260 pub fn to_rust_boxed<T>(&self, instance: Instance) -> errors::Result<Box<T>>
1262 where
1263 T: DeserializeOwned + Any,
1264 {
1265 macro_rules! rust_box_from_java_object {
1267 ($jni_transformation:path) => {{
1268 let object_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1270 self.jni_env,
1271 instance.jinstance,
1272 cache::get_get_object_method()?,
1273 );
1274 let object_instance =
1275 jni_utils::create_global_ref_from_local_ref(object_instance, self.jni_env)?;
1276 let v = Box::new($jni_transformation(object_instance, self.jni_env)?);
1277 let v_any = v as Box<dyn Any>;
1278
1279 jni_utils::delete_java_ref(self.jni_env, object_instance);
1280
1281 match v_any.downcast::<T>() {
1282 Ok(v) => Ok(v),
1283 Err(error) => Err(errors::J4RsError::RustError(format!(
1284 "Could not downcast to Rust type: {:?}",
1285 error
1286 ))),
1287 }
1288 }};
1289 }
1290
1291 let t_type = TypeId::of::<T>();
1292
1293 unsafe {
1294 let object_class_name_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1296 self.jni_env,
1297 instance.jinstance,
1298 cache::get_get_object_class_name_method()?,
1299 );
1300 let object_class_name_instance = jni_utils::create_global_ref_from_local_ref(
1301 object_class_name_instance,
1302 self.jni_env,
1303 )?;
1304 let class_name =
1305 &(jni_utils::string_from_jobject(object_class_name_instance, self.jni_env)?);
1306 jni_utils::delete_java_ref(self.jni_env, object_class_name_instance);
1307 if t_type == TypeId::of::<String>() && JavaClass::String.get_class_str() == class_name {
1308 rust_box_from_java_object!(jni_utils::string_from_jobject)
1309 } else if t_type == TypeId::of::<i32>()
1310 && (JavaClass::Integer.get_class_str() == class_name || PRIMITIVE_INT == class_name)
1311 {
1312 rust_box_from_java_object!(jni_utils::i32_from_jobject)
1313 } else if t_type == TypeId::of::<i8>()
1314 && (JavaClass::Byte.get_class_str() == class_name || PRIMITIVE_BYTE == class_name)
1315 {
1316 rust_box_from_java_object!(jni_utils::i8_from_jobject)
1317 } else if t_type == TypeId::of::<i16>()
1318 && (JavaClass::Short.get_class_str() == class_name || PRIMITIVE_SHORT == class_name)
1319 {
1320 rust_box_from_java_object!(jni_utils::i16_from_jobject)
1321 } else if t_type == TypeId::of::<u16>()
1322 && (JavaClass::Character.get_class_str() == class_name
1323 || 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>>() && PRIMITIVE_BYTE_ARRAY == class_name {
1340 rust_box_from_java_object!(jni_utils::i8_array_from_jobject)
1341 } else if t_type == TypeId::of::<Vec<i16>>() && PRIMITIVE_SHORT_ARRAY == class_name {
1342 rust_box_from_java_object!(jni_utils::i16_array_from_jobject)
1343 } else if t_type == TypeId::of::<Vec<u16>>() && PRIMITIVE_CHAR_ARRAY == class_name {
1344 rust_box_from_java_object!(jni_utils::u16_array_from_jobject)
1345 } else if t_type == TypeId::of::<Vec<i32>>() && PRIMITIVE_INT_ARRAY == class_name {
1346 rust_box_from_java_object!(jni_utils::i32_array_from_jobject)
1347 } else if t_type == TypeId::of::<Vec<i64>>() && PRIMITIVE_LONG_ARRAY == class_name {
1348 rust_box_from_java_object!(jni_utils::i64_array_from_jobject)
1349 } else if t_type == TypeId::of::<Vec<f32>>() && PRIMITIVE_FLOAT_ARRAY == class_name {
1350 rust_box_from_java_object!(jni_utils::f32_array_from_jobject)
1351 } else if t_type == TypeId::of::<Vec<f64>>() && PRIMITIVE_DOUBLE_ARRAY == class_name {
1352 rust_box_from_java_object!(jni_utils::f64_array_from_jobject)
1353 } else if t_type == TypeId::of::<Vec<bool>>() && PRIMITIVE_BOOLEAN_ARRAY == class_name {
1354 rust_box_from_java_object!(jni_utils::boolean_array_from_jobject)
1355 } else {
1356 Ok(Box::new(self.to_rust_deserialized(instance)?))
1357 }
1358 }
1359 }
1360
1361 pub fn to_rust<T>(&self, instance: Instance) -> errors::Result<T>
1363 where
1364 T: DeserializeOwned + Any,
1365 {
1366 self.to_rust_boxed(instance).map(|v| *v)
1367 }
1368
1369 pub fn to_rust_deserialized<T>(&self, instance: Instance) -> errors::Result<T>
1370 where
1371 T: DeserializeOwned + Any,
1372 {
1373 unsafe {
1374 debug("Invoking the getJson method");
1375 let json_instance = (opt_to_res(cache::get_jni_call_object_method())?)(
1377 self.jni_env,
1378 instance.jinstance,
1379 cache::get_get_json_method()?,
1380 );
1381 let _ = Self::do_return(self.jni_env, "")?;
1382 debug("Transforming jstring to rust String");
1383 let global_json_instance =
1384 jni_utils::create_global_ref_from_local_ref(json_instance, self.jni_env)?;
1385 let json = jni_utils::jstring_to_rust_string(self, global_json_instance as jstring)?;
1386 jni_utils::delete_java_ref(self.jni_env, global_json_instance);
1387 Self::do_return(self.jni_env, serde_json::from_str(&json)?)
1388 }
1389 }
1390
1391 pub fn deploy_artifact<T: Any + JavaArtifact>(&self, artifact: &T) -> errors::Result<()> {
1397 self.do_deploy_artifact(artifact, "org.astonbitecode.j4rs.api.deploy.SimpleMavenDeployer")
1398 }
1399
1400 pub fn deploy_artifact_and_deps(&self, artifact: &MavenArtifact) -> errors::Result<()> {
1406 self.do_deploy_artifact(artifact, "org.astonbitecode.j4rs.api.deploy.MavenDeployer")
1407 }
1408
1409 pub fn do_deploy_artifact<T: Any + JavaArtifact>(&self, artifact: &T, deployer_class: &str) -> errors::Result<()> {
1410 let artifact = artifact as &dyn Any;
1411 if let Some(maven_artifact) = artifact.downcast_ref::<MavenArtifact>() {
1412 let mut found = false;
1413 for repo in get_maven_settings().repos.into_iter() {
1414 let instance = self.create_instance(
1415 deployer_class,
1416 &[
1417 InvocationArg::try_from(repo.uri)?,
1418 InvocationArg::try_from(&maven_artifact.base)?,
1419 ],
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 found = true;
1435 break;
1436 }
1437 }
1438 if !found {
1439 Err(J4RsError::GeneralError(format!(
1440 "Could not deploy {}:{}:{}",
1441 maven_artifact.group, maven_artifact.id, maven_artifact.version
1442 )))
1443 } else {
1444 Ok(())
1445 }
1446 } else if let Some(local_jar_artifact) = artifact.downcast_ref::<LocalJarArtifact>() {
1447 let instance = self.create_instance(
1448 "org.astonbitecode.j4rs.api.deploy.FileSystemDeployer",
1449 &[InvocationArg::try_from(&local_jar_artifact.base)?],
1450 )?;
1451
1452 let _ = self.invoke(
1453 &instance,
1454 "deploy",
1455 &[InvocationArg::try_from(&local_jar_artifact.path)?],
1456 )?;
1457 Ok(())
1458 } else {
1459 Err(J4RsError::GeneralError(format!(
1460 "Don't know how to deploy artifacts of {:?}",
1461 artifact.type_id()
1462 )))
1463 }
1464 }
1465
1466 pub fn copy_j4rs_libs_under<P: AsRef<Path>>(path: P) -> errors::Result<()> {
1472 let mut pb = PathBuf::from(path.as_ref());
1473 pb.push("deps");
1474 fs::create_dir_all(&pb)?;
1475
1476 let default_jassets_path_buf = utils::default_jassets_path()?;
1477 let default_jassets_path_string = default_jassets_path_buf.to_str().unwrap().to_owned();
1478
1479 let options = &mut fs_extra::dir::CopyOptions::new();
1481 options.overwrite = true;
1482 let _ = fs_extra::copy_items(vec![default_jassets_path_string].as_ref(), path, options)?;
1483
1484 let dynlibs: Vec<String> = {
1486 let mut dynlibs = vec![];
1487 for _i in 0..10 {
1490 dynlibs = utils::find_j4rs_dynamic_libraries_paths()?;
1491 if dynlibs.is_empty() {
1492 thread::sleep(time::Duration::from_millis(1000));
1493 } else {
1494 break;
1495 }
1496 }
1497 dynlibs
1498 };
1499 if dynlibs.is_empty() {
1500 let message = format!(
1501 "No j4rs dynamic libraries found for target triple {}. \
1502 The host triple during build is {}.",
1503 env::var("TARGET").unwrap_or("".to_string()),
1504 env::var("HOST").unwrap_or("UNKNOWN".to_string())
1505 );
1506 println!("cargo:warning={}", message);
1507 }
1508
1509 let _ = fs_extra::copy_items(&dynlibs, &pb, options)?;
1510
1511 Ok(())
1512 }
1513
1514 pub fn chain(&self, instance: &Instance) -> errors::Result<ChainableInstance<'_>> {
1516 ChainableInstance::new_with_instance_ref(instance, self)
1517 }
1518
1519 pub fn into_chain(&self, instance: Instance) -> ChainableInstance<'_> {
1521 ChainableInstance::new(instance, self)
1522 }
1523
1524 pub fn throw_invocation_exception(&self, message: &str) -> errors::Result<()> {
1526 unsafe {
1527 let _ = jni_utils::throw_exception(message, self.jni_env)?;
1528 }
1529 Ok(())
1530 }
1531
1532 pub(crate) fn do_return<T>(jni_env: *mut JNIEnv, to_return: T) -> errors::Result<T> {
1533 unsafe {
1534 if (opt_to_res(cache::get_jni_exception_check())?)(jni_env) == JNI_TRUE {
1535 let throwable = (opt_to_res(cache::get_jni_exception_occured())?)(jni_env);
1536 let throwable_string = Self::get_throwable_string(throwable, jni_env)?;
1537 (opt_to_res(cache::get_jni_exception_clear())?)(jni_env);
1538 Err(J4RsError::JavaError(throwable_string))
1539 } else {
1540 Ok(to_return)
1541 }
1542 }
1543 }
1544
1545 unsafe fn get_throwable_string(
1546 throwable: jobject,
1547 jni_env: *mut JNIEnv,
1548 ) -> errors::Result<String> {
1549 let java_string = (opt_to_res(cache::get_jni_call_static_object_method())?)(
1550 jni_env,
1551 cache::get_utils_class()?,
1552 cache::get_utils_exception_to_string_method()?,
1553 throwable,
1554 );
1555 let to_ret = jni_utils::string_from_jobject(java_string, jni_env);
1556 jni_utils::delete_java_local_ref(jni_env, java_string);
1557 to_ret
1558 }
1559
1560 fn get_created_vm() -> Option<*mut JNIEnv> {
1562 unsafe {
1563 let mut created_vms_size: jsize = 0;
1565 tweaks::get_created_java_vms(
1566 &mut Vec::with_capacity(created_vms_size as usize),
1567 0,
1568 &mut created_vms_size,
1569 );
1570
1571 if created_vms_size == 0 {
1572 None
1573 } else {
1574 debug(&format!(
1575 "Retrieving the first of {} created JVMs",
1576 created_vms_size
1577 ));
1578 let mut buffer: Vec<*mut JavaVM> = Vec::with_capacity(2);
1580 for _ in 0..created_vms_size {
1581 buffer.push(ptr::null_mut());
1582 }
1583
1584 let retjint = tweaks::get_created_java_vms(
1585 &mut buffer,
1586 created_vms_size,
1587 &mut created_vms_size,
1588 );
1589 if retjint == JNI_OK {
1590 let act = (**buffer[0]).v1_4.AttachCurrentThread;
1591 let mut jni_environment: *mut JNIEnv = ptr::null_mut();
1592 (act)(
1593 buffer[0],
1594 (&mut jni_environment as *mut *mut JNIEnv) as *mut *mut c_void,
1595 ptr::null_mut(),
1596 );
1597 Some(jni_environment)
1598 } else {
1599 error(&format!(
1600 "Error while retrieving the created JVMs: {}",
1601 retjint
1602 ));
1603 None
1604 }
1605 }
1606 }
1607 }
1608
1609 fn detach_current_thread(&self) {
1610 unsafe {
1611 let mut created_vms_size: jsize = 0;
1613 tweaks::get_created_java_vms(
1614 &mut Vec::with_capacity(created_vms_size as usize),
1615 0,
1616 &mut created_vms_size,
1617 );
1618
1619 if created_vms_size > 0 {
1620 let mut buffer: Vec<*mut JavaVM> = Vec::with_capacity(created_vms_size as usize);
1622 for _ in 0..created_vms_size {
1623 buffer.push(ptr::null_mut());
1624 }
1625
1626 let retjint = tweaks::get_created_java_vms(
1627 &mut buffer,
1628 created_vms_size,
1629 &mut created_vms_size,
1630 );
1631 if retjint == JNI_OK {
1632 let dct = (**buffer[0]).v1_4.DetachCurrentThread;
1633 (dct)(buffer[0]);
1634 } else {
1635 warn(&format!(
1636 "Error while retrieving the created JVMs: {}",
1637 retjint
1638 ));
1639 }
1640 }
1641 }
1642 }
1643
1644 pub fn select(instance_receivers: &[&InstanceReceiver]) -> errors::Result<(usize, Instance)> {
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 thread::yield_now();
1657 }
1658 }
1659
1660 pub fn select_timeout(
1667 instance_receivers: &[&InstanceReceiver],
1668 timeout: &time::Duration,
1669 ) -> errors::Result<(usize, Instance)> {
1670 let start = time::Instant::now();
1671 loop {
1672 for (index, ir) in instance_receivers.iter().enumerate() {
1673 let res = ir.rx.try_recv();
1674 if res.is_ok() {
1675 return Ok((index, res.unwrap()));
1676 }
1677 }
1678 if &start.elapsed() > timeout {
1679 return Err(J4RsError::Timeout);
1680 }
1681 thread::yield_now();
1682 }
1683 }
1684}
1685
1686impl Drop for Jvm {
1687 fn drop(&mut self) {
1688 if cache::remove_active_jvm() <= 0 {
1689 if self.detach_thread_on_drop {
1690 self.detach_current_thread();
1691 }
1692 cache::set_thread_local_env(None);
1693 }
1694 }
1695}
1696
1697pub struct JvmBuilder<'a> {
1699 classpath_entries: Vec<ClasspathEntry>,
1700 java_opts: Vec<JavaOpt<'a>>,
1701 no_implicit_classpath: bool,
1702 detach_thread_on_drop: bool,
1703 lib_name_opt: Option<String>,
1704 skip_setting_native_lib: bool,
1705 base_path: Option<PathBuf>,
1706 maven_settings: MavenSettings,
1707 javafx: bool,
1708 default_classloader: bool,
1709 java_vm_opt: Option<*mut JavaVM>,
1710 jobject_within_valid_classloader_opt: Option<jobject>,
1711}
1712
1713impl<'a> JvmBuilder<'a> {
1714 pub fn new<'b>() -> JvmBuilder<'b> {
1716 JvmBuilder {
1717 classpath_entries: Vec::new(),
1718 java_opts: Vec::new(),
1719 no_implicit_classpath: false,
1720 detach_thread_on_drop: true,
1721 lib_name_opt: None,
1722 skip_setting_native_lib: false,
1723 base_path: None,
1724 maven_settings: MavenSettings::default(),
1725 javafx: false,
1726 default_classloader: false,
1727 java_vm_opt: None,
1728 jobject_within_valid_classloader_opt: None,
1729 }
1730 }
1731
1732 pub fn classpath_entry(&'a mut self, cp_entry: ClasspathEntry) -> &'a mut JvmBuilder<'a> {
1734 self.classpath_entries.push(cp_entry);
1735 self
1736 }
1737
1738 pub fn classpath_entries(
1740 &'a mut self,
1741 cp_entries: Vec<ClasspathEntry>,
1742 ) -> &'a mut JvmBuilder<'a> {
1743 for cp_entry in cp_entries {
1744 self.classpath_entries.push(cp_entry);
1745 }
1746 self
1747 }
1748
1749 pub fn java_opt(&'a mut self, opt: JavaOpt<'a>) -> &'a mut JvmBuilder<'a> {
1751 self.java_opts.push(opt);
1752 self
1753 }
1754
1755 pub fn java_opts(&'a mut self, opts: Vec<JavaOpt<'a>>) -> &'a mut JvmBuilder<'a> {
1757 for opt in opts {
1758 self.java_opts.push(opt);
1759 }
1760 self
1761 }
1762
1763 pub fn with_no_implicit_classpath(&'a mut self) -> &'a mut JvmBuilder<'a> {
1766 self.no_implicit_classpath = true;
1767 self
1768 }
1769
1770 pub fn detach_thread_on_drop(
1776 &'a mut self,
1777 detach_thread_on_drop: bool,
1778 ) -> &'a mut JvmBuilder<'a> {
1779 self.detach_thread_on_drop = detach_thread_on_drop;
1780 self
1781 }
1782
1783 pub fn with_native_lib_name(&'a mut self, lib_name: &str) -> &'a mut JvmBuilder<'a> {
1788 self.lib_name_opt = Some(lib_name.to_string());
1789 self
1790 }
1791
1792 pub fn skip_setting_native_lib(&'a mut self) -> &'a mut JvmBuilder<'a> {
1795 self.skip_setting_native_lib = true;
1796 self
1797 }
1798
1799 pub fn with_base_path<P: AsRef<Path>>(&'a mut self, base_path: P) -> &'a mut JvmBuilder<'a> {
1802 self.base_path = Some(base_path.as_ref().to_owned());
1803 self
1804 }
1805
1806 pub fn with_maven_settings(
1808 &'a mut self,
1809 maven_settings: MavenSettings,
1810 ) -> &'a mut JvmBuilder<'a> {
1811 self.maven_settings = maven_settings;
1812 self
1813 }
1814
1815 pub fn with_javafx_support(&'a mut self) -> &'a mut JvmBuilder<'a> {
1817 self.javafx = true;
1818 self
1819 }
1820
1821 pub fn with_java_vm(&'a mut self, java_vm: *mut JavaVM) -> &'a mut JvmBuilder<'a> {
1825 self.java_vm_opt = Some(java_vm);
1826 self
1827 }
1828
1829 pub fn with_classloader_of_activity(
1847 &'a mut self,
1848 jobject_within_valid_classloader: jobject,
1849 ) -> &'a mut JvmBuilder<'a> {
1850 self.jobject_within_valid_classloader_opt = Some(jobject_within_valid_classloader);
1851 let tmp = self.detach_thread_on_drop(false);
1856 let tmp = tmp.with_no_implicit_classpath();
1857 tmp
1858 }
1859
1860 pub fn with_default_classloader(&'a mut self) -> &'a mut JvmBuilder<'a> {
1884 self.default_classloader = true;
1885 self
1886 }
1887
1888 pub fn build(&mut self) -> errors::Result<Jvm> {
1890 if !self.default_classloader {
1891 self.java_opts.push(JavaOpt::new(
1893 "-Djava.system.class.loader=org.astonbitecode.j4rs.api.deploy.J4rsClassLoader",
1894 ));
1895 self.java_opts.push(JavaOpt::new("-Xshare:off"));
1896 self.java_opts.push(JavaOpt::new(
1897 "-Djdk.net.URLClassPath.showIgnoredClassPathEntries=true",
1898 ));
1899 }
1900
1901 let classpath = if self.no_implicit_classpath {
1902 self.classpath_entries
1903 .iter()
1904 .fold(".".to_string(), |all, elem| {
1905 format!("{}{}{}", all, utils::classpath_sep(), elem.to_string())
1906 })
1907 } else {
1908 let jassets_path = self.get_jassets_path()?;
1910 let j4rs_jar_to_use = format!("j4rs-{}-jar-with-dependencies.jar", j4rs_version());
1912 let j4rs_testing_jar_to_use = format!("j4rs-testing-{}.jar", j4rs_version());
1913 let j4rs_javafx_jar_to_use = format!("j4rs-javafx-{}.jar", j4rs_version());
1914 let mut cp_string = String::new();
1916 for entry in std::fs::read_dir(jassets_path)? {
1917 let path = entry?.path();
1918 if let Some(file_name) = opt_to_res(path.file_name())?.to_str() {
1919 if !file_name.contains("j4rs-")
1920 || file_name.ends_with(&j4rs_jar_to_use)
1921 || file_name.ends_with(&j4rs_testing_jar_to_use)
1922 || file_name.ends_with(&j4rs_javafx_jar_to_use)
1923 {
1924 if !cp_string.is_empty() {
1925 cp_string.push_str(utils::classpath_sep());
1926 }
1927 if let Some(path) = path.to_str() {
1928 cp_string.push_str(path);
1929 }
1930 }
1931 }
1932 }
1933
1934 let default_class_path = format!("-Djava.class.path={}", cp_string);
1935
1936 self.classpath_entries
1937 .iter()
1938 .fold(default_class_path, |all, elem| {
1939 format!("{}{}{}", all, utils::classpath_sep(), elem.to_string())
1940 })
1941 };
1942 info(&format!("Setting classpath to {}", classpath));
1943
1944 let mut jvm_options = if self.no_implicit_classpath {
1946 vec![classpath]
1947 } else {
1948 let default_library_path = utils::java_library_path()?;
1949 info(&format!("Setting library path to {}", default_library_path));
1950 vec![classpath, default_library_path]
1951 };
1952
1953 if self.javafx {
1954 let jassets_path = self.get_jassets_path()?;
1955 let jassets_path_string = jassets_path.to_str().unwrap_or(".");
1956 let modules_path = format!("--module-path {}", jassets_path_string);
1957 jvm_options.push(modules_path);
1958 jvm_options.push(
1959 "--add-modules javafx.base,javafx.controls,javafx.graphics,javafx.fxml".to_string(),
1960 );
1961 }
1962 self.java_opts
1963 .clone()
1964 .into_iter()
1965 .for_each(|opt| jvm_options.push(opt.to_string()));
1966
1967 let lib_name_opt = if self.lib_name_opt.is_none()
1969 && !self.skip_setting_native_lib
1970 && cfg!(not(target_os = "android"))
1971 {
1972 let deps_dir = utils::deps_dir()?;
1973 let found_libs: Vec<String> = if Path::new(&deps_dir).exists() {
1974 utils::find_j4rs_dynamic_libraries_names()?
1975 } else {
1976 let default_lib_name = if cfg!(windows) {
1979 "l4rs.dll".to_string()
1980 } else {
1981 "libj4rs.so".to_string()
1982 };
1983 info(&format!(
1984 "Deps directory not found. Setting the library name to search to default: {}",
1985 default_lib_name
1986 ));
1987 vec![default_lib_name]
1988 };
1989
1990 let lib_name_opt = if !found_libs.is_empty() {
1991 let a_lib = found_libs[0].clone().replace("lib", "");
1992
1993 let dot_splitted: Vec<&str> = a_lib.split('.').collect();
1994 let name = dot_splitted[0].to_string();
1995 info(&format!(
1996 "Passing to the Java world the name of the library to load: {}",
1997 name
1998 ));
1999 Some(name)
2000 } else {
2001 None
2002 };
2003 lib_name_opt
2004 } else if self.lib_name_opt.is_some() && !self.skip_setting_native_lib {
2005 let name = self.lib_name_opt.clone();
2006 info(&format!(
2007 "Passing to the Java world the name of the library to load: {}",
2008 name.as_ref().unwrap()
2009 ));
2010 name
2011 } else {
2012 None
2013 };
2014
2015 provisioning::set_maven_settings(&self.maven_settings);
2016
2017 let jvm_res = if self.java_vm_opt.is_some() {
2018 set_java_vm(self.java_vm_opt.unwrap());
2020 Jvm::attach_thread()
2021 } else {
2022 Jvm::new(&jvm_options, lib_name_opt)
2023 };
2024
2025 jvm_res.and_then(|mut jvm| {
2026 if !self.detach_thread_on_drop {
2027 jvm.detach_thread_on_drop(false);
2028 }
2029 if self.jobject_within_valid_classloader_opt.is_some() {
2030 cache_classloader_of(
2031 jvm.jni_env,
2032 self.jobject_within_valid_classloader_opt.unwrap(),
2033 )?;
2034 }
2035 Ok(jvm)
2036 })
2037 }
2038
2039 pub fn already_initialized() -> errors::Result<Jvm> {
2043 Jvm::new(&[], None)
2044 }
2045
2046 fn get_jassets_path(&self) -> errors::Result<PathBuf> {
2047 match &self.base_path {
2048 Some(base_path_string) => {
2049 let mut pb = PathBuf::from(base_path_string);
2050 pb.push("jassets");
2051 let mut global_jassets_path_opt = cache::JASSETS_PATH.lock()?;
2052 *global_jassets_path_opt = Some(pb.clone());
2053 Ok(pb)
2054 }
2055 None => utils::default_jassets_path(),
2056 }
2057 }
2058}
2059
2060pub enum JavaClass<'a> {
2062 Void,
2063 String,
2064 Boolean,
2065 Byte,
2066 Character,
2067 Short,
2068 Integer,
2069 Long,
2070 Float,
2071 Double,
2072 List,
2073 Of(&'a str),
2074}
2075
2076impl<'a> JavaClass<'a> {
2077 pub fn get_class_str(&self) -> &'a str {
2078 match self {
2079 Self::Void => "void",
2080 Self::String => CLASS_STRING,
2081 Self::Boolean => CLASS_BOOLEAN,
2082 Self::Byte => CLASS_BYTE,
2083 Self::Character => CLASS_CHARACTER,
2084 Self::Short => CLASS_SHORT,
2085 Self::Integer => CLASS_INTEGER,
2086 Self::Long => CLASS_LONG,
2087 Self::Float => CLASS_FLOAT,
2088 Self::Double => CLASS_DOUBLE,
2089 Self::List => CLASS_LIST,
2090 Self::Of(str) => str,
2091 }
2092 }
2093}
2094
2095impl<'a> From<JavaClass<'a>> for &'a str {
2096 fn from(java_class: JavaClass<'a>) -> &'a str {
2097 java_class.get_class_str()
2098 }
2099}
2100
2101impl<'a> From<&'a str> for JavaClass<'a> {
2102 fn from(java_class: &'a str) -> JavaClass<'a> {
2103 match java_class {
2104 "void" => Self::Void,
2105 CLASS_STRING => Self::String,
2106 CLASS_BOOLEAN => Self::Boolean,
2107 CLASS_BYTE => Self::Byte,
2108 CLASS_CHARACTER => Self::Character,
2109 CLASS_SHORT => Self::Short,
2110 CLASS_INTEGER => Self::Integer,
2111 CLASS_LONG => Self::Long,
2112 CLASS_FLOAT => Self::Float,
2113 CLASS_DOUBLE => Self::Double,
2114 CLASS_LIST => Self::List,
2115 str => Self::Of(str),
2116 }
2117 }
2118}
2119
2120pub enum Null<'a> {
2125 String,
2126 Boolean,
2127 Byte,
2128 Character,
2129 Short,
2130 Integer,
2131 Long,
2132 Float,
2133 Double,
2134 List,
2135 Of(&'a str),
2136}
2137
2138#[derive(Debug, Clone)]
2140pub struct ClasspathEntry(PathBuf);
2141
2142impl ClasspathEntry {
2143 pub fn new<P: AsRef<Path>>(classpath_entry: P) -> ClasspathEntry {
2144 ClasspathEntry(classpath_entry.as_ref().to_owned())
2145 }
2146}
2147
2148impl ToString for ClasspathEntry {
2149 fn to_string(&self) -> String {
2150 self.0.to_string_lossy().to_string()
2151 }
2152}
2153
2154#[derive(Debug, Clone)]
2156pub struct JavaOpt<'a>(&'a str);
2157
2158impl<'a> JavaOpt<'a> {
2159 pub fn new(java_opt: &str) -> JavaOpt<'_> {
2160 JavaOpt(java_opt)
2161 }
2162}
2163
2164impl<'a> ToString for JavaOpt<'a> {
2165 fn to_string(&self) -> String {
2166 self.0.to_string()
2167 }
2168}
2169
2170#[cfg(test)]
2171mod api_unit_tests {
2172 use super::*;
2173 use crate::lib_unit_tests::create_tests_jvm;
2174
2175 #[test]
2176 fn jvm_builder() -> errors::Result<()> {
2177 let res = create_tests_jvm();
2178 assert!(res.is_ok());
2179 let one_more_res = JvmBuilder::already_initialized();
2180 assert!(one_more_res.is_ok());
2181
2182 Ok(())
2183 }
2184
2185 #[test]
2186 fn test_copy_j4rs_libs_under() -> errors::Result<()> {
2187 let newdir = "./newdir";
2188 Jvm::copy_j4rs_libs_under(newdir)?;
2189
2190 let _ = std::fs::remove_dir_all(newdir);
2191
2192 Ok(())
2193 }
2194
2195 #[test]
2196 fn test_select() -> errors::Result<()> {
2197 let (tx1, rx1) = channel();
2198 let ir1 = InstanceReceiver::new(rx1, 0);
2199 let (_tx2, rx2) = channel();
2200 let ir2 = InstanceReceiver::new(rx2, 0);
2201 let (tx3, rx3) = channel();
2202 let ir3 = InstanceReceiver::new(rx3, 0);
2203
2204 thread::spawn(move || {
2205 let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2206 thread::sleep(time::Duration::from_millis(10));
2208 let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2209 thread::sleep(time::Duration::from_millis(10));
2210 let _ = tx3.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2211 });
2212
2213 let (index1, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2214 let (index2, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2215 let (index3, _) = Jvm::select(&[&ir1, &ir2, &ir3]).unwrap();
2216 assert_eq!(index1, 2);
2217 assert_eq!(index2, 0);
2218 assert_eq!(index3, 2);
2219
2220 Ok(())
2221 }
2222
2223 #[test]
2224 fn test_select_timeout() -> errors::Result<()> {
2225 let (tx1, rx1) = channel();
2226 let ir1 = InstanceReceiver::new(rx1, 0);
2227 let (tx2, rx2) = channel();
2228 let ir2 = InstanceReceiver::new(rx2, 0);
2229
2230 thread::spawn(move || {
2231 let _ = tx1.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2232 thread::sleep(time::Duration::from_millis(10));
2234 let _ = tx2.send(Instance::new(ptr::null_mut(), CLASS_STRING).unwrap());
2235 });
2236
2237 let d = time::Duration::from_millis(500);
2238 let (index1, _) = Jvm::select_timeout(&[&ir1, &ir2], &d)?;
2239 let (index2, _) = Jvm::select_timeout(&[&ir1, &ir2], &d)?;
2240 assert!(Jvm::select_timeout(&[&ir1, &ir2], &d).is_err());
2241 assert_eq!(index1, 0);
2242 assert_eq!(index2, 1);
2243
2244 Ok(())
2245 }
2246
2247 #[test]
2248 fn test_java_class_creation() -> errors::Result<()> {
2249 assert_eq!(JavaClass::Void.get_class_str(), "void");
2250 assert_eq!(JavaClass::String.get_class_str(), CLASS_STRING);
2251 assert_eq!(JavaClass::Boolean.get_class_str(), CLASS_BOOLEAN);
2252 assert_eq!(JavaClass::Byte.get_class_str(), CLASS_BYTE);
2253 assert_eq!(JavaClass::Character.get_class_str(), CLASS_CHARACTER);
2254 assert_eq!(JavaClass::Short.get_class_str(), CLASS_SHORT);
2255 assert_eq!(JavaClass::Integer.get_class_str(), CLASS_INTEGER);
2256 assert_eq!(JavaClass::Long.get_class_str(), CLASS_LONG);
2257 assert_eq!(JavaClass::Float.get_class_str(), CLASS_FLOAT);
2258 assert_eq!(JavaClass::Double.get_class_str(), CLASS_DOUBLE);
2259 assert_eq!(JavaClass::List.get_class_str(), CLASS_LIST);
2260 assert_eq!(
2261 JavaClass::Of("a.java.Class").get_class_str(),
2262 "a.java.Class"
2263 );
2264
2265 Ok(())
2266 }
2267
2268 #[test]
2269 fn test_byte_array_to_rust() -> errors::Result<()> {
2270 let jvm = create_tests_jvm()?;
2271 let rust_value: Vec<i8> = vec![-3_i8, 7_i8, 8_i8];
2272 let ia: Vec<_> = rust_value
2273 .iter()
2274 .map(|x| {
2275 InvocationArg::try_from(x)
2276 .unwrap()
2277 .into_primitive()
2278 .unwrap()
2279 })
2280 .collect();
2281 let java_instance = jvm.create_java_array(PRIMITIVE_BYTE, &ia)?;
2282 let rust_value_from_java: Vec<i8> = jvm.to_rust(java_instance)?;
2283 assert_eq!(rust_value_from_java, rust_value);
2284
2285 Ok(())
2286 }
2287
2288 #[test]
2289 fn test_short_array_to_rust() -> errors::Result<()> {
2290 let jvm = create_tests_jvm()?;
2291 let rust_value: Vec<i16> = vec![-3_i16, 7_i16, 10000_i16];
2292 let ia: Vec<_> = rust_value
2293 .iter()
2294 .map(|x| {
2295 InvocationArg::try_from(x)
2296 .unwrap()
2297 .into_primitive()
2298 .unwrap()
2299 })
2300 .collect();
2301 let java_instance = jvm.create_java_array(PRIMITIVE_SHORT, &ia)?;
2302 let rust_value_from_java: Vec<i16> = jvm.to_rust(java_instance)?;
2303 assert_eq!(rust_value_from_java, rust_value);
2304
2305 Ok(())
2306 }
2307
2308 #[test]
2309 fn test_char_array_to_rust() -> errors::Result<()> {
2310 let jvm = create_tests_jvm()?;
2311 let rust_value: Vec<u16> = vec![3_u16, 7_u16, 10000_u16];
2312 let ia: Vec<_> = rust_value
2313 .iter()
2314 .map(|x| {
2315 InvocationArg::try_from(x)
2316 .unwrap()
2317 .into_primitive()
2318 .unwrap()
2319 })
2320 .collect();
2321 let java_instance = jvm.create_java_array(PRIMITIVE_CHAR, &ia)?;
2322 let rust_value_from_java: Vec<u16> = jvm.to_rust(java_instance)?;
2323 assert_eq!(rust_value_from_java, rust_value);
2324
2325 Ok(())
2326 }
2327
2328 #[test]
2329 fn test_int_array_to_rust() -> errors::Result<()> {
2330 let jvm = create_tests_jvm()?;
2331 let rust_value: Vec<i32> = vec![-100_000, -1_000_000, 1_000_000];
2332 let ia: Vec<_> = rust_value
2333 .iter()
2334 .map(|x| {
2335 InvocationArg::try_from(x)
2336 .unwrap()
2337 .into_primitive()
2338 .unwrap()
2339 })
2340 .collect();
2341 let java_instance = jvm.create_java_array(PRIMITIVE_INT, &ia)?;
2342 let rust_value_from_java: Vec<i32> = jvm.to_rust(java_instance)?;
2343 assert_eq!(rust_value_from_java, rust_value);
2344
2345 Ok(())
2346 }
2347
2348 #[test]
2349 fn test_long_array_to_rust() -> errors::Result<()> {
2350 let jvm = create_tests_jvm()?;
2351 let rust_value: Vec<i64> = vec![-100_000, -1_000_000, 1_000_000];
2352 let ia: Vec<_> = rust_value
2353 .iter()
2354 .map(|x| {
2355 InvocationArg::try_from(x)
2356 .unwrap()
2357 .into_primitive()
2358 .unwrap()
2359 })
2360 .collect();
2361 let java_instance = jvm.create_java_array(PRIMITIVE_LONG, &ia)?;
2362 let rust_value_from_java: Vec<i64> = jvm.to_rust(java_instance)?;
2363 assert_eq!(rust_value_from_java, rust_value);
2364
2365 Ok(())
2366 }
2367
2368 #[test]
2369 fn test_float_array_to_rust() -> errors::Result<()> {
2370 let jvm = create_tests_jvm()?;
2371 let rust_value: Vec<f32> = vec![3_f32, 7.5_f32, -1000.5_f32];
2372 let ia: Vec<_> = rust_value
2373 .iter()
2374 .map(|x| {
2375 InvocationArg::try_from(x)
2376 .unwrap()
2377 .into_primitive()
2378 .unwrap()
2379 })
2380 .collect();
2381 let java_instance = jvm.create_java_array(PRIMITIVE_FLOAT, &ia)?;
2382 let rust_value_from_java: Vec<f32> = jvm.to_rust(java_instance)?;
2383 assert_eq!(rust_value_from_java, rust_value);
2384
2385 Ok(())
2386 }
2387
2388 #[test]
2389 fn test_double_array_to_rust() -> errors::Result<()> {
2390 let jvm = create_tests_jvm()?;
2391 let rust_value: Vec<f64> = vec![3_f64, 7.5_f64, -1000.5_f64];
2392 let ia: Vec<_> = rust_value
2393 .iter()
2394 .map(|x| {
2395 InvocationArg::try_from(x)
2396 .unwrap()
2397 .into_primitive()
2398 .unwrap()
2399 })
2400 .collect();
2401 let java_instance = jvm.create_java_array(PRIMITIVE_DOUBLE, &ia)?;
2402 let rust_value_from_java: Vec<f64> = jvm.to_rust(java_instance)?;
2403 assert_eq!(rust_value_from_java, rust_value);
2404
2405 Ok(())
2406 }
2407
2408 #[test]
2409 fn test_boolean_array_to_rust() -> errors::Result<()> {
2410 let jvm = create_tests_jvm()?;
2411 let rust_value: Vec<bool> = vec![false, true, false];
2412 let ia: Vec<_> = rust_value
2413 .iter()
2414 .map(|x| {
2415 InvocationArg::try_from(x)
2416 .unwrap()
2417 .into_primitive()
2418 .unwrap()
2419 })
2420 .collect();
2421 let java_instance = jvm.create_java_array(PRIMITIVE_BOOLEAN, &ia)?;
2422 let rust_value_from_java: Vec<bool> = jvm.to_rust(java_instance)?;
2423 assert_eq!(rust_value_from_java, rust_value);
2424
2425 Ok(())
2426 }
2427
2428 #[test]
2429 fn test_int_to_rust() -> errors::Result<()> {
2430 let jvm = create_tests_jvm()?;
2431 let rust_value: i32 = 3;
2432 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2433 let java_instance = jvm.create_instance(CLASS_INTEGER, &[ia])?;
2434 let java_primitive_instance =
2435 jvm.invoke(&java_instance, "intValue", InvocationArg::empty())?;
2436 let rust_value_from_java: i32 = jvm.to_rust(java_instance)?;
2437 assert_eq!(rust_value_from_java, rust_value);
2438 let rust_value_from_java: i32 = jvm.to_rust(java_primitive_instance)?;
2439 assert_eq!(rust_value_from_java, rust_value);
2440
2441 Ok(())
2442 }
2443
2444 #[test]
2445 fn test_byte_to_rust() -> errors::Result<()> {
2446 let jvm = create_tests_jvm()?;
2447 let rust_value: i8 = 3;
2448 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2449 let java_instance = jvm.create_instance(CLASS_BYTE, &[ia])?;
2450 let java_primitive_instance =
2451 jvm.invoke(&java_instance, "byteValue", InvocationArg::empty())?;
2452 let rust_value_from_java: i8 = jvm.to_rust(java_instance)?;
2453 assert_eq!(rust_value_from_java, rust_value);
2454 let rust_value_from_java: i8 = jvm.to_rust(java_primitive_instance)?;
2455 assert_eq!(rust_value_from_java, rust_value);
2456
2457 Ok(())
2458 }
2459
2460 #[test]
2461 fn test_short_to_rust() -> errors::Result<()> {
2462 let jvm = create_tests_jvm()?;
2463 let rust_value: i16 = 3;
2464 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2465 let java_instance = jvm.create_instance(CLASS_SHORT, &[ia])?;
2466 let java_primitive_instance =
2467 jvm.invoke(&java_instance, "shortValue", InvocationArg::empty())?;
2468 let rust_value_from_java: i16 = jvm.to_rust(java_instance)?;
2469 assert_eq!(rust_value_from_java, rust_value);
2470 let rust_value_from_java: i16 = jvm.to_rust(java_primitive_instance)?;
2471 assert_eq!(rust_value_from_java, rust_value);
2472
2473 Ok(())
2474 }
2475
2476 #[test]
2477 fn test_char_to_rust() -> errors::Result<()> {
2478 let jvm = create_tests_jvm()?;
2479 let rust_value: u16 = 3;
2480 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2481 let java_instance = jvm.create_instance(CLASS_CHARACTER, &[ia])?;
2482 let java_primitive_instance =
2483 jvm.invoke(&java_instance, "charValue", InvocationArg::empty())?;
2484 let rust_value_from_java: u16 = jvm.to_rust(java_instance)?;
2485 assert_eq!(rust_value_from_java, rust_value);
2486 let rust_value_from_java: u16 = jvm.to_rust(java_primitive_instance)?;
2487 assert_eq!(rust_value_from_java, rust_value);
2488
2489 Ok(())
2490 }
2491
2492 #[test]
2493 fn test_long_to_rust() -> errors::Result<()> {
2494 let jvm = create_tests_jvm()?;
2495 let rust_value: i64 = 3;
2496 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2497 let java_instance = jvm.create_instance(CLASS_LONG, &[ia])?;
2498 let java_primitive_instance =
2499 jvm.invoke(&java_instance, "longValue", InvocationArg::empty())?;
2500 let rust_value_from_java: i64 = jvm.to_rust(java_instance)?;
2501 assert_eq!(rust_value_from_java, rust_value);
2502 let rust_value_from_java: i64 = jvm.to_rust(java_primitive_instance)?;
2503 assert_eq!(rust_value_from_java, rust_value);
2504
2505 Ok(())
2506 }
2507
2508 #[test]
2509 fn test_float_to_rust() -> errors::Result<()> {
2510 let jvm = create_tests_jvm()?;
2511 let rust_value: f32 = 3.3;
2512 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2513 let java_instance = jvm.create_instance(CLASS_FLOAT, &[ia])?;
2514 let java_primitive_instance =
2515 jvm.invoke(&java_instance, "floatValue", InvocationArg::empty())?;
2516 let rust_value_from_java: f32 = jvm.to_rust(java_instance)?;
2517 assert_eq!(rust_value_from_java, rust_value);
2518 let rust_value_from_java: f32 = jvm.to_rust(java_primitive_instance)?;
2519 assert_eq!(rust_value_from_java, rust_value);
2520
2521 Ok(())
2522 }
2523
2524 #[test]
2525 fn test_double_to_rust() -> errors::Result<()> {
2526 let jvm = create_tests_jvm()?;
2527 let rust_value: f64 = 3.3;
2528 let ia = InvocationArg::try_from(rust_value)?.into_primitive()?;
2529 let java_instance = jvm.create_instance(CLASS_DOUBLE, &[ia])?;
2530 let java_primitive_instance =
2531 jvm.invoke(&java_instance, "doubleValue", InvocationArg::empty())?;
2532 let rust_value_from_java: f64 = jvm.to_rust(java_instance)?;
2533 assert_eq!(rust_value_from_java, rust_value);
2534 let rust_value_from_java: f64 = jvm.to_rust(java_primitive_instance)?;
2535 assert_eq!(rust_value_from_java, rust_value);
2536
2537 Ok(())
2538 }
2539
2540 #[test]
2541 fn api_by_ref_or_value() -> errors::Result<()> {
2542 let jvm = create_tests_jvm()?;
2543
2544 let inv_arg1 = InvocationArg::try_from("some string")?;
2546 let _ = jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", &[&inv_arg1])?;
2547 let _ = jvm.create_instance("java.lang.String", &[inv_arg1])?;
2548 Ok(())
2549 }
2550
2551 #[test]
2552 fn exception_string_in_the_result() -> errors::Result<()> {
2553 let jvm = create_tests_jvm()?;
2554
2555 let res = jvm.create_instance("non.Existing", InvocationArg::empty());
2556 assert!(res.is_err());
2557 let exception_sttring = format!("{}", res.err().unwrap());
2558 assert!(exception_sttring.contains("Cannot create instance of non.Existing"));
2559
2560 Ok(())
2561 }
2562}