1extern crate libc;
25#[macro_use]
26extern crate log;
27extern crate serde;
28extern crate serde_json;
29
30use futures::channel::oneshot;
31use std::mem;
32use std::os::raw::c_void;
33use std::sync::mpsc::Sender;
34
35pub use jni_sys;
36use jni_sys::{jlong, jobject, jstring, JNIEnv};
37
38pub use api::instance::Instance;
39pub use api::instance::InstanceReceiver;
40
41pub use self::api::invocation_arg::InvocationArg;
42pub use self::api::Callback;
43pub use self::api::ClasspathEntry;
44pub use self::api::JavaClass;
45pub use self::api::JavaOpt;
46pub use self::api::Jvm;
47pub use self::api::JvmBuilder;
48pub use self::api::Null;
49pub use self::api_tweaks::{get_created_java_vms, set_java_vm};
50pub use self::jni_utils::jstring_to_rust_string;
51pub use self::provisioning::LocalJarArtifact;
52pub use self::provisioning::MavenArtifact;
53pub use self::provisioning::MavenArtifactRepo;
54pub use self::provisioning::MavenSettings;
55
56mod api;
57pub(crate) mod api_tweaks;
58pub mod async_api;
59mod cache;
60pub mod errors;
61pub mod jfx;
62mod jni_utils;
63mod logger;
64pub mod prelude;
65mod provisioning;
66mod utils;
67
68pub fn new_jvm(
70 classpath_entries: Vec<ClasspathEntry>,
71 java_opts: Vec<JavaOpt>,
72) -> errors::Result<Jvm> {
73 JvmBuilder::new()
74 .classpath_entries(classpath_entries)
75 .java_opts(java_opts)
76 .build()
77}
78
79#[no_mangle]
80pub extern "C" fn Java_org_astonbitecode_j4rs_api_invocation_NativeCallbackToRustChannelSupport_docallbacktochannel(
81 _jni_env: *mut JNIEnv,
82 _class: *const c_void,
83 ptr_address: jlong,
84 java_instance: jobject,
85) {
86 let mut jvm = Jvm::attach_thread()
87 .expect("Could not create a j4rs Jvm while invoking callback to channel.");
88 jvm.detach_thread_on_drop(false);
89 let instance_res = Instance::from_jobject_with_global_ref(java_instance);
90 if let Ok(instance) = instance_res {
91 let p = ptr_address as *mut Sender<Instance>;
92 let tx = unsafe { Box::from_raw(p) };
93
94 let result = tx.send(instance);
95 mem::forget(tx);
96 if let Err(error) = result {
97 panic!(
98 "Could not send to the defined callback channel: {:?}",
99 error
100 );
101 }
102 } else {
103 panic!("Could not create Rust Instance from the Java Instance object...");
104 }
105}
106
107#[no_mangle]
108pub extern "C" fn Java_org_astonbitecode_j4rs_api_invocation_NativeCallbackToRustFutureSupport_docallbacktochannel(
109 _jni_env: *mut JNIEnv,
110 _class: *const c_void,
111 ptr_address: jlong,
112 java_instance: jobject,
113) {
114 let mut jvm = Jvm::attach_thread().expect(
115 "Could not create a j4rs Jvm while invoking callback to channel for completing a Future.",
116 );
117 jvm.detach_thread_on_drop(false);
118 let instance_res = Instance::from_jobject_with_global_ref(java_instance);
119 if let Ok(instance) = instance_res {
120 let p = ptr_address as *mut oneshot::Sender<errors::Result<Instance>>;
121 let tx = unsafe { Box::from_raw(p) };
122
123 let result = tx.send(Ok(instance));
124 if let Err(_) = result {
125 panic!("Could not send to the defined callback channel to complete the future");
126 }
127 } else {
128 panic!("Could not create Rust Instance from the Java Instance object...");
129 }
130}
131
132#[no_mangle]
133pub unsafe extern "C" fn Java_org_astonbitecode_j4rs_api_invocation_NativeCallbackToRustFutureSupport_failcallbacktochannel(
134 _jni_env: *mut JNIEnv,
135 _class: *const c_void,
136 ptr_address: jlong,
137 stacktrace: jstring,
138) {
139 let mut jvm = Jvm::attach_thread().expect(
140 "Could not create a j4rs Jvm while invoking callback to channel for failing a Future.",
141 );
142 jvm.detach_thread_on_drop(false);
143 let stacktrace = jstring_to_rust_string(&jvm, stacktrace);
144 if let Ok(st) = stacktrace {
145 let p = ptr_address as *mut oneshot::Sender<errors::Result<Instance>>;
146 let tx = unsafe { Box::from_raw(p) };
147
148 let result = tx.send(Err(errors::J4RsError::JavaError(st)));
149 if let Err(_) = result {
150 panic!("Could not send to the defined callback channel to fail a future");
151 }
152 } else {
153 panic!("Could not create Rust String from the Java jstring while invoking callback to channel for failing a Future...");
154 }
155}
156
157#[cfg(test)]
158mod lib_unit_tests {
159 use std::collections::HashMap;
160 use std::convert::TryFrom;
161 use std::path::MAIN_SEPARATOR;
162 use std::ptr::null_mut;
163 use std::thread::JoinHandle;
164 use std::{thread, time};
165 use std::sync::{LazyLock, Mutex};
166 use crate::api::{self, JavaClass};
167 use crate::provisioning::JavaArtifact;
168 use crate::{LocalJarArtifact, MavenArtifactRepo, MavenSettings, Null};
169 use super::utils::jassets_path;
170 use super::{errors, InvocationArg, Jvm, JvmBuilder, MavenArtifact};
171
172 static SYNC_GUARD: LazyLock<Mutex<()>> = LazyLock::new(|| {
173 Mutex::new(())
174 });
175
176 pub(crate) fn create_tests_jvm() -> errors::Result<Jvm> {
177 let jvm: Jvm = JvmBuilder::new().build()?;
178 {
179 let _guard = SYNC_GUARD.lock().unwrap();
180 jvm.deploy_artifact(&MavenArtifact::from(format!("io.github.astonbitecode:j4rs-testing:{}", api::j4rs_version()).as_str()))?;
181 }
182 Ok(jvm)
183 }
184
185 #[test]
186 fn create_instance_and_invoke() -> errors::Result<()> {
187 let jvm = create_tests_jvm()?;
188 let instantiation_args = vec![InvocationArg::try_from("arg from Rust")?];
189 let instance = jvm.create_instance("java.lang.String", instantiation_args.as_ref());
190 match instance {
191 Ok(i) => {
192 let invocation_args = vec![InvocationArg::try_from(" ")?];
193 let invocation_result = jvm.invoke(&i, "split", &invocation_args);
194 assert!(invocation_result.is_ok());
195 }
196 Err(error) => {
197 panic!("ERROR when creating Instance: {:?}", error);
198 }
199 };
200
201 let instantiation_args_2 = vec![InvocationArg::try_from("arg from Rust")?];
202 let instance_2 = jvm.create_instance("java.lang.String", instantiation_args_2.as_ref());
203 match instance_2 {
204 Ok(i) => {
205 let invocation_args = vec![InvocationArg::try_from(" ")?];
206 let invocation_result = jvm.invoke(&i, "split", &invocation_args);
207 assert!(invocation_result.is_ok());
208 }
209 Err(error) => {
210 panic!("ERROR when creating Instance: {:?}", error);
211 }
212 };
213
214 let static_invocation_result =
215 jvm.invoke_static("java.lang.System", "currentTimeMillis", InvocationArg::empty());
216 assert!(static_invocation_result.is_ok());
217
218 Ok(())
219 }
220
221 #[test]
222 fn init_callback_channel() -> errors::Result<()> {
223 let jvm = create_tests_jvm()?;
224 match jvm.create_instance(
225 "org.astonbitecode.j4rs.tests.MySecondTest",
226 InvocationArg::empty(),
227 ) {
228 Ok(i) => {
229 let instance_receiver_res = jvm.init_callback_channel(&i);
230 assert!(instance_receiver_res.is_ok());
231 let instance_receiver = instance_receiver_res?;
232 assert!(jvm.invoke(&i, "performCallback", InvocationArg::empty()).is_ok());
233 let res_chan = instance_receiver.rx().recv();
234 let i = res_chan?;
235 let res_to_rust = jvm.to_rust(i);
236 assert!(res_to_rust.is_ok());
237 let _: String = res_to_rust?;
238 let millis = time::Duration::from_millis(500);
239 thread::sleep(millis);
240 }
241 Err(error) => {
242 panic!("ERROR when creating Instance: {:?}", error);
243 }
244 }
245
246 Ok(())
247 }
248
249 #[test]
250 fn callback_to_channel() -> errors::Result<()> {
251 let jvm = create_tests_jvm()?;
252 match jvm.create_instance(
253 "org.astonbitecode.j4rs.tests.MySecondTest",
254 InvocationArg::empty(),
255 ) {
256 Ok(i) => {
257 let instance_receiver_res =
258 jvm.invoke_to_channel(&i, "performCallback", InvocationArg::empty());
259 assert!(instance_receiver_res.is_ok());
260 let instance_receiver = instance_receiver_res?;
261 let res_chan = instance_receiver.rx().recv();
262 let i = res_chan?;
263 let res_to_rust = jvm.to_rust(i);
264 assert!(res_to_rust.is_ok());
265 let _: String = res_to_rust?;
266 let millis = time::Duration::from_millis(500);
267 thread::sleep(millis);
268 }
269 Err(error) => {
270 panic!("ERROR when creating Instance: {:?}", error);
271 }
272 }
273
274 Ok(())
275 }
276
277 #[test]
278 fn multiple_callbacks_to_channel() -> errors::Result<()> {
279 let jvm = create_tests_jvm()?;
280 match jvm.create_instance(
281 "org.astonbitecode.j4rs.tests.MySecondTest",
282 InvocationArg::empty(),
283 ) {
284 Ok(i) => {
285 let instance_receiver_res =
286 jvm.invoke_to_channel(&i, "performTenCallbacks", InvocationArg::empty());
287 assert!(instance_receiver_res.is_ok());
288 let instance_receiver = instance_receiver_res?;
289 for _i in 0..10 {
290 let thousand_millis = time::Duration::from_millis(1000);
291 let res_chan = instance_receiver.rx().recv_timeout(thousand_millis);
292 let i = res_chan.unwrap();
293 let res_to_rust = jvm.to_rust(i);
294 assert!(res_to_rust.is_ok());
295 let _: String = res_to_rust?;
296 }
297 let millis = time::Duration::from_millis(500);
298 thread::sleep(millis);
299 }
300 Err(error) => {
301 panic!("ERROR when creating Instance: {:?}", error);
302 }
303 }
304
305 Ok(())
306 }
307
308 #[test]
309 fn multiple_callbacks_to_channel_from_multiple_threads() -> errors::Result<()> {
310 let jvm = create_tests_jvm()?;
311 match jvm.create_instance(
312 "org.astonbitecode.j4rs.tests.MySecondTest",
313 InvocationArg::empty(),
314 ) {
315 Ok(i) => {
316 let instance_receiver_res =
317 jvm.invoke_to_channel(&i, "performCallbackFromTenThreads", InvocationArg::empty());
318 assert!(instance_receiver_res.is_ok());
319 let instance_receiver = instance_receiver_res?;
320 for _i in 0..10 {
321 let thousand_millis = time::Duration::from_millis(1000);
322 let res_chan = instance_receiver.rx().recv_timeout(thousand_millis);
323 let i = res_chan.unwrap();
324 let res_to_rust = jvm.to_rust(i);
325 assert!(res_to_rust.is_ok());
326 let _: String = res_to_rust?;
327 }
328 let millis = time::Duration::from_millis(500);
329 thread::sleep(millis);
330 }
331 Err(error) => {
332 panic!("ERROR when creating Instance: {:?}", error);
333 }
334 }
335
336 Ok(())
337 }
338
339 fn _memory_leaks_invoke_instances_to_channel() -> errors::Result<()> {
342 let jvm = create_tests_jvm()?;
343 match jvm.create_instance(
344 "org.astonbitecode.j4rs.tests.MySecondTest",
345 InvocationArg::empty(),
346 ) {
347 Ok(instance) => {
348 for i in 0..100000000 {
349 let instance_receiver = jvm
350 .invoke_to_channel(&instance, "performCallback", InvocationArg::empty())
351 ?;
352 let thousand_millis = time::Duration::from_millis(1000);
353 let res = instance_receiver.rx().recv_timeout(thousand_millis);
354 if i % 100000 == 0 {
355 println!("{}: {}", i, res.is_ok());
356 }
357 }
358 }
359 Err(error) => {
360 panic!("ERROR when creating Instance: {:?}", error);
361 }
362 }
363
364 let thousand_millis = time::Duration::from_millis(1000);
365 thread::sleep(thousand_millis);
366
367 Ok(())
368 }
369
370 #[test]
371 fn clone_instance() -> errors::Result<()> {
372 let jvm = create_tests_jvm()?;
373 let i_result =
375 jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty());
376 assert!(i_result.is_ok());
377 let i_arg = i_result?;
378
379 let i1 = jvm.clone_instance(&i_arg)?;
381 let i2 = jvm.clone_instance(&i_arg)?;
382 let invocation_res = jvm.create_instance(
384 "org.astonbitecode.j4rs.tests.MyTest",
385 &[InvocationArg::from(i1)],
386 );
387 assert!(invocation_res.is_ok());
388 let invocation_res = jvm.create_instance(
389 "org.astonbitecode.j4rs.tests.MyTest",
390 &[InvocationArg::from(i2)],
391 );
392 assert!(invocation_res.is_ok());
393
394 Ok(())
395 }
396
397 fn _memory_leaks_create_instances() -> errors::Result<()> {
400 let jvm = create_tests_jvm()?;
401
402 for i in 0..100000000 {
403 match jvm.create_instance(
404 "org.astonbitecode.j4rs.tests.MySecondTest",
405 InvocationArg::empty(),
406 ) {
407 Ok(instance) => {
408 if i % 100000 == 0 {
409 println!("{}: {}", i, instance.class_name());
410 }
411 }
412 Err(error) => {
413 panic!("ERROR when creating Instance: {:?}", error);
414 }
415 }
416 }
417 let thousand_millis = time::Duration::from_millis(1000);
418 thread::sleep(thousand_millis);
419
420 Ok(())
421 }
422
423 fn _memory_leaks_invoke_instances() -> errors::Result<()> {
426 let jvm = create_tests_jvm()?;
427 match jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty()) {
428 Ok(instance) => {
429 let inv_arg = InvocationArg::try_from("tests")?;
430 for i in 0..100000000 {
431 if i % 100000 == 0 {
432 println!("{}", i);
433 }
434 jvm.invoke(&instance, "getMyWithArgs", &[&inv_arg])?;
435 }
436 }
437 Err(error) => {
438 panic!("ERROR when creating Instance: {:?}", error);
439 }
440 }
441
442 let thousand_millis = time::Duration::from_millis(1000);
443 thread::sleep(thousand_millis);
444
445 Ok(())
446 }
447
448 fn _memory_leaks_invoke_instances_and_to_rust() -> errors::Result<()> {
451 let jvm = create_tests_jvm()?;
452 match jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty()) {
453 Ok(instance) => {
454 for i in 0..100000000 {
455 let ret_instance = jvm
456 .invoke(
457 &instance,
458 "echo",
459 &[InvocationArg::try_from(33333333_i32)?],
460 )?;
461 let v: i32 = jvm.to_rust(ret_instance)?;
462 if i % 100000 == 0 {
463 println!("{}: {}", i, v);
464 }
465 }
466 }
467 Err(error) => {
468 panic!("ERROR when creating Instance: {:?}", error);
469 }
470 }
471
472 let thousand_millis = time::Duration::from_millis(1000);
473 thread::sleep(thousand_millis);
474
475 Ok(())
476 }
477
478 fn _memory_leaks_invoke_instances_w_new_invarg() -> errors::Result<()> {
481 let jvm = create_tests_jvm()?;
482 let mut string_arg_rust = "".to_string();
483 for _ in 0..100 {
484 string_arg_rust = format!("{}{}", string_arg_rust, "astring")
485 }
486 match jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty()) {
487 Ok(instance) => {
488 for i in 0..100000000 {
489 if i % 100000 == 0 {
490 println!("{}", i);
491 }
492 let _ia = InvocationArg::try_from(&string_arg_rust)?;
493 jvm.invoke(&instance, "getMyWithArgs", &[_ia])?;
494 }
495 }
496 Err(error) => {
497 panic!("ERROR when creating Instance: {:?}", error);
498 }
499 }
500
501 let thousand_millis = time::Duration::from_millis(1000);
502 thread::sleep(thousand_millis);
503
504 Ok(())
505 }
506
507 fn _memory_leaks_create_instances_in_different_threads() -> errors::Result<()> {
510 for i in 0..100000000 {
511 thread::spawn(move || {
512 let jvm = create_tests_jvm().unwrap();
513 match jvm.create_instance(
514 "org.astonbitecode.j4rs.tests.MySecondTest",
515 InvocationArg::empty(),
516 ) {
517 Ok(_) => {
518 if i % 100000 == 0 {
519 println!("{}", i);
520 }
521 }
522 Err(error) => {
523 panic!("ERROR when creating Instance: {:?}", error);
524 }
525 };
526 });
527
528 let millis = time::Duration::from_millis(10);
529 thread::sleep(millis);
530 }
531
532 Ok(())
533 }
534
535 #[test]
536 fn cast() -> errors::Result<()> {
537 let jvm = create_tests_jvm()?;
538
539 let instantiation_args = vec![InvocationArg::try_from("Hi")?];
540 let instance = jvm
541 .create_instance("java.lang.String", instantiation_args.as_ref())?;
542 jvm.cast(&instance, "java.lang.Object")?;
543
544 Ok(())
545 }
546
547 #[test]
548 fn invoke_vec() -> errors::Result<()> {
549 let jvm = create_tests_jvm()?;
550
551 match jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty()) {
552 Ok(i) => {
553 let invocation_args = vec![
555 InvocationArg::try_from("arg1"),
556 InvocationArg::try_from("arg2"),
557 InvocationArg::try_from("arg3"),
558 InvocationArg::try_from("arg33"),
559 ];
560 let list_instance = jvm.java_list("java.lang.String", invocation_args)?;
561 let res = jvm.invoke(&i, "list", &[InvocationArg::from(list_instance)]);
562 assert!(res.is_ok());
563 let instance = jvm.create_instance(
565 "java.lang.String",
566 &[InvocationArg::try_from("astring")?],
567 );
568 let list_instance = jvm.java_list("java.lang.String", vec![instance])?;
569 let res = jvm.invoke(&i, "list", &[InvocationArg::from(list_instance)]);
570 assert!(res.is_ok());
571 let list_instance = jvm
573 .java_list(JavaClass::String, vec!["arg1", "arg2", "arg3", "arg33"])?;
574 let res = jvm.invoke(&i, "list", &[InvocationArg::from(list_instance)]);
575 assert!(res.is_ok());
576 }
577 Err(error) => {
578 panic!("ERROR when creating Instance: {:?}", error);
579 }
580 }
581
582 Ok(())
583 }
584
585 #[test]
586 fn invoke_map() -> errors::Result<()> {
587 let jvm = create_tests_jvm()?;
588
589 match jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty()) {
590 Ok(i) => {
591 let map = HashMap::from([("Potatoes", 3), ("Tomatoes", 33), ("Carrotoes", 333)]);
592 let map_instance = jvm
593 .java_map(JavaClass::String, JavaClass::Integer, map)?;
594 let res = jvm.invoke(&i, "map", &[InvocationArg::from(map_instance)]);
595 assert!(res.is_ok());
596 }
597 Err(error) => {
598 panic!("ERROR when creating Instance: {:?}", error);
599 }
600 }
601
602 Ok(())
603 }
604
605 #[test]
606 fn multithread() -> errors::Result<()> {
607 let v: Vec<JoinHandle<String>> = (0..10)
608 .map(|i: i8| {
609 let v = thread::spawn(move || {
610 let jvm = create_tests_jvm().unwrap();
611 let instantiation_args =
612 vec![InvocationArg::try_from(format!("Thread{}", i)).unwrap()];
613 let instance = jvm
614 .create_instance("java.lang.String", instantiation_args.as_ref()).unwrap();
615 let string: String = jvm.to_rust(instance).unwrap();
616 string
617 });
618 v
619 })
620 .collect();
621
622 for jh in v {
623 let str = jh.join();
624 println!("{}", str.unwrap());
625 }
626
627 Ok(())
628 }
629
630 #[test]
631 fn use_a_java_instance_in_different_thread() -> errors::Result<()> {
632 let jvm = create_tests_jvm()?;
633 let instantiation_args = vec![InvocationArg::try_from("3")?];
634 let instance = jvm
635 .create_instance("java.lang.String", instantiation_args.as_ref())
636 ?;
637
638 let jh = thread::spawn(move || {
639 let jvm = create_tests_jvm()?;
640 let res = jvm.invoke(&instance, "isEmpty", InvocationArg::empty());
641 res
642 });
643
644 let join_res = jh.join();
645 assert!(join_res.is_ok());
646 assert!(join_res.unwrap().is_ok());
647
648 Ok(())
649 }
650
651 #[test]
652 fn drop_and_attach_main_thread() -> errors::Result<()> {
653 let tid = format!("{:?}", thread::current().id());
654 {
655 let jvm = create_tests_jvm()?;
656 let instantiation_args = vec![InvocationArg::try_from(tid.clone())?];
657 let instance = jvm
658 .create_instance("java.lang.String", instantiation_args.as_ref())
659 ?;
660 let tid_from_java: &String = &(jvm.to_rust(instance)?);
661 assert!(&tid == tid_from_java);
662 }
663 {
664 let jvm = create_tests_jvm()?;
665 let instantiation_args = vec![InvocationArg::try_from(tid.clone())?];
666 let instance = jvm
667 .create_instance("java.lang.String", instantiation_args.as_ref())
668 ?;
669 let tid_from_java: &String = &(jvm.to_rust(instance)?);
670 assert!(&tid == tid_from_java);
671 }
672
673 Ok(())
674 }
675
676 #[test]
677 fn drop_and_attach_other_thread() -> errors::Result<()> {
678 let _: Jvm = super::new_jvm(Vec::new(), Vec::new())?;
679 let jh = thread::spawn(move || {
680 let tid = format!("{:?}", thread::current().id());
681 {
682 let jvm = create_tests_jvm().unwrap();
683 let instantiation_args = vec![InvocationArg::try_from(tid.clone()).unwrap()];
684 let instance = jvm
685 .create_instance("java.lang.String", instantiation_args.as_ref())
686 .unwrap();
687 let tid_from_java: &String = &jvm.to_rust(instance).unwrap();
688 assert!(&tid == tid_from_java);
689 }
690 {
691 let jvm = create_tests_jvm().unwrap();
692 let instantiation_args = vec![InvocationArg::try_from(tid.clone()).unwrap()];
693 let instance = jvm
694 .create_instance("java.lang.String", instantiation_args.as_ref())
695 .unwrap();
696 let tid_from_java: &String = &jvm.to_rust(instance).unwrap();
697 assert!(&tid == tid_from_java);
698 }
699 true
700 });
701
702 assert!(jh.join().unwrap());
703
704 Ok(())
705 }
706
707 #[test]
708 fn deploy_maven_artifact() -> errors::Result<()> {
709 let jvm = create_tests_jvm()?;
710 assert!(jvm
711 .deploy_artifact(&MavenArtifact::from("io.github.astonbitecode:j4rs:0.22.0"))
712 .is_ok());
713 let to_remove = format!(
714 "{}{}j4rs-0.22.0.jar",
715 jassets_path().unwrap().to_str().unwrap(),
716 MAIN_SEPARATOR
717 );
718 let _ = std::fs::remove_file(to_remove);
719
720 assert!(jvm.deploy_artifact(&UnknownArtifact {}).is_err());
721
722 Ok(())
723 }
724
725 #[test]
726 fn deploy_maven_artifact_with_transitive_deps() -> errors::Result<()> {
727 let jvm = create_tests_jvm()?;
728 assert!(jvm
729 .deploy_artifact_and_deps(&MavenArtifact::from("org.openjfx:javafx-graphics:21.0.9"))
730 .is_ok());
731
732 let to_remove1 = format!(
733 "{}{}javafx-graphics-21.0.9.jar",
734 jassets_path().unwrap().to_str().unwrap(),
735 MAIN_SEPARATOR
736 );
737 std::fs::remove_file(to_remove1)?;
738
739 let to_remove2 = format!(
740 "{}{}javafx-base-21.0.9.jar",
741 jassets_path().unwrap().to_str().unwrap(),
742 MAIN_SEPARATOR
743 );
744 std::fs::remove_file(to_remove2)?;
745
746 Ok(())
747 }
748
749 #[test]
750 fn deploy_maven_artifact_from_more_artifactories() -> errors::Result<()> {
751 let jvm: Jvm = JvmBuilder::new()
752 .with_maven_settings(MavenSettings::new(vec![
753 MavenArtifactRepo::from("myrepo1::https://my.repo.io/artifacts"),
754 MavenArtifactRepo::from("myrepo2::https://my.other.repo.io/artifacts"),
755 ]))
756 .build()?;
757 assert!(jvm
758 .deploy_artifact(&MavenArtifact::from("io.github.astonbitecode:j4rs:0.22.0"))
759 .is_ok());
760 let to_remove = format!(
761 "{}{}j4rs-0.22.0.jar",
762 jassets_path().unwrap().to_str().unwrap(),
763 MAIN_SEPARATOR
764 );
765 let _ = std::fs::remove_dir_all(to_remove);
766
767 Ok(())
768 }
769
770 #[test]
771 fn deploy_local_artifact() -> errors::Result<()> {
772 let jvm: Jvm = super::new_jvm(Vec::new(), Vec::new())?;
773 assert!(jvm
774 .deploy_artifact(&LocalJarArtifact::from("./non_existing.jar"))
775 .is_err());
776
777 Ok(())
778 }
779
780 struct UnknownArtifact {}
781
782 impl JavaArtifact for UnknownArtifact {}
783
784 #[test]
785 fn variadic_constructor() -> errors::Result<()> {
786 let jvm = create_tests_jvm()?;
787
788 let s1 = InvocationArg::try_from("abc")?;
789 let s2 = InvocationArg::try_from("def")?;
790 let s3 = InvocationArg::try_from("ghi")?;
791
792 let arr_instance = jvm
793 .create_java_array("java.lang.String", &vec![s1, s2, s3])
794 ?;
795
796 let test_instance = jvm
797 .create_instance(
798 "org.astonbitecode.j4rs.tests.MyTest",
799 &[InvocationArg::from(arr_instance)],
800 )
801 ?;
802
803 let i = jvm.invoke(&test_instance, "getMyString", InvocationArg::empty())?;
804
805 let s: String = jvm.to_rust(i)?;
806 assert!(s == "abc, def, ghi");
807
808 Ok(())
809 }
810
811 #[test]
812 fn variadic_string_method() -> errors::Result<()> {
813 let jvm = create_tests_jvm()?;
814 let test_instance = jvm
815 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
816 ?;
817
818 let s1 = InvocationArg::try_from("abc")?;
819 let s2 = InvocationArg::try_from("def")?;
820 let s3 = InvocationArg::try_from("ghi")?;
821
822 let arr_instance = jvm
823 .create_java_array("java.lang.String", &vec![s1, s2, s3])
824 ?;
825
826 let i = jvm
827 .invoke(
828 &test_instance,
829 "getMyWithArgsList",
830 &[InvocationArg::from(arr_instance)],
831 )
832 ?;
833
834 let s: String = jvm.to_rust(i)?;
835 assert!(s == "abcdefghi");
836
837 Ok(())
838 }
839
840 #[test]
841 fn variadic_int_method() -> errors::Result<()> {
842 let jvm = create_tests_jvm()?;
843 let test_instance = jvm
844 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
845 ?;
846
847 let s1 = InvocationArg::try_from(1)?;
848 let s2 = InvocationArg::try_from(2)?;
849 let s3 = InvocationArg::try_from(3)?;
850
851 let arr_instance = jvm
852 .create_java_array("java.lang.Integer", &vec![s1, s2, s3])
853 ?;
854
855 let i = jvm
856 .invoke(
857 &test_instance,
858 "addInts",
859 &[InvocationArg::from(arr_instance)],
860 )
861 ?;
862
863 let num: i32 = jvm.to_rust(i)?;
864 assert!(num == 6);
865
866 Ok(())
867 }
868
869 #[test]
870 fn variadic_long_primitive_method() -> errors::Result<()> {
871 let jvm = create_tests_jvm()?;
872 let values: Vec<i64> = vec![1, 2, 3];
873 let jargs: Vec<_> = values
874 .into_iter()
875 .map(|v| {
876 InvocationArg::try_from(v)
877 .unwrap()
878 .into_primitive()
879 .unwrap()
880 })
881 .collect();
882
883 let arr_instance = jvm.create_java_array("long", &jargs)?;
884
885 let _ = jvm
886 .invoke_static(
887 "org.astonbitecode.j4rs.tests.MyTest",
888 "useLongPrimitivesArray",
889 &[InvocationArg::from(arr_instance)],
890 )
891 ?;
892
893 Ok(())
894 }
895
896 #[test]
897 fn instance_invocation_chain_and_collect() -> errors::Result<()> {
898 let jvm = create_tests_jvm()?;
899 let instance = jvm
900 .create_instance(
901 "org.astonbitecode.j4rs.tests.MyTest",
902 &[InvocationArg::try_from("string")?],
903 )
904 ?;
905
906 let i1 = jvm
907 .chain(&instance)
908 ?
909 .invoke(
910 "appendToMyString",
911 &[InvocationArg::try_from("_is_appended")?],
912 )
913 ?
914 .invoke("length", InvocationArg::empty())
915 ?
916 .collect();
917
918 let product: isize = jvm.to_rust(i1)?;
919
920 assert!(product == 18);
921
922 Ok(())
923 }
924
925 #[test]
926 fn instance_invocation_chain_and_to_rust() -> errors::Result<()> {
927 let jvm = create_tests_jvm()?;
928 let instance = jvm
929 .create_instance(
930 "org.astonbitecode.j4rs.tests.MyTest",
931 &[InvocationArg::try_from("string")?],
932 )
933 ?;
934
935 let product: isize = jvm
936 .into_chain(instance)
937 .invoke(
938 "appendToMyString",
939 &[InvocationArg::try_from("_is_appended")?],
940 )
941 ?
942 .invoke("length", InvocationArg::empty())
943 ?
944 .to_rust()
945 ?;
946
947 assert!(product == 18);
948
949 Ok(())
950 }
951
952 #[test]
953 fn static_invocation_chain_and_to_rust() -> errors::Result<()> {
954 let jvm = create_tests_jvm()?;
955
956 let static_invocation = jvm.static_class("java.lang.System")?;
957
958 let _: isize = jvm
959 .into_chain(static_invocation)
960 .invoke("currentTimeMillis", InvocationArg::empty())
961 ?
962 .to_rust()
963 ?;
964
965 Ok(())
966 }
967
968 #[test]
969 fn access_class_field_and_enum() -> errors::Result<()> {
970 let jvm = create_tests_jvm()?;
971
972 let static_invocation = jvm.static_class("java.lang.System")?;
973 let field_instance_res = jvm.field(&static_invocation, "out");
974 assert!(field_instance_res.is_ok());
975
976 let access_mode_enum = jvm.static_class("java.nio.file.AccessMode")?;
977 let access_mode_write = jvm.field(&access_mode_enum, "WRITE");
978 assert!(access_mode_write.is_ok());
979
980 Ok(())
981 }
982
983 #[test]
984 fn java_hello_world() -> errors::Result<()> {
985 let jvm = create_tests_jvm()?;
986
987 let system = jvm.static_class("java.lang.System")?;
988 let _ = jvm
989 .into_chain(system)
990 .field("out")
991 ?
992 .invoke(
993 "println",
994 &[InvocationArg::try_from("Hello World")?],
995 )
996 ?
997 .collect();
998
999 Ok(())
1000 }
1001
1002 #[test]
1003 fn parent_interface_method() -> errors::Result<()> {
1004 let jvm = create_tests_jvm()?;
1005 let instance = jvm
1006 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1007 ?;
1008
1009 let size: isize = jvm
1010 .into_chain(instance)
1011 .invoke("getMap", InvocationArg::empty())
1012 ?
1013 .cast("java.util.Map")
1014 ?
1015 .invoke("size", InvocationArg::empty())
1016 ?
1017 .to_rust()
1018 ?;
1019
1020 assert!(size == 2);
1021
1022 Ok(())
1023 }
1024
1025 #[test]
1026 fn invoke_generic_method() -> errors::Result<()> {
1027 let jvm = create_tests_jvm()?;
1028
1029 let instance = jvm
1031 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1032 ?;
1033
1034 let dummy_map = jvm.invoke(&instance, "getMap", InvocationArg::empty())?;
1036
1037 let _ = jvm
1039 .invoke(
1040 &dummy_map,
1041 "put",
1042 &[InvocationArg::try_from("three")?,
1043 InvocationArg::try_from(3)?],
1044 )
1045 ?;
1046
1047 let size: isize = jvm
1049 .into_chain(dummy_map)
1050 .invoke("size", InvocationArg::empty())
1051 ?
1052 .to_rust()
1053 ?;
1054
1055 assert!(size == 3);
1056
1057 Ok(())
1058 }
1059
1060 #[test]
1061 fn invoke_method_with_primitive_args() -> errors::Result<()> {
1062 let jvm = create_tests_jvm()?;
1063
1064 let ia = InvocationArg::try_from(1_i32)
1067 ?
1068 .into_primitive()
1069 ?;
1070 let res1 = jvm.create_instance("java.lang.Integer", &[ia]);
1071 assert!(res1.is_ok());
1072
1073 let ia1 = InvocationArg::try_from(1_i32)?;
1075 let ia2 = InvocationArg::try_from(1_i32)?;
1076 let test_instance = jvm
1077 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1078 ?;
1079 let res2 = jvm.invoke(
1080 &test_instance,
1081 "addInts",
1082 &[ia1.into_primitive()?, ia2.into_primitive()?],
1083 );
1084 assert!(res2.is_ok());
1085
1086 Ok(())
1087 }
1088
1089 #[test]
1090 fn to_tust_returns_list() -> errors::Result<()> {
1091 let jvm = create_tests_jvm()?;
1092 let test_instance = jvm
1093 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1094 ?;
1095 let list_instance = jvm
1096 .invoke(
1097 &test_instance,
1098 "getNumbersUntil",
1099 &[InvocationArg::try_from(10_i32)?],
1100 )
1101 ?;
1102 let vec: Vec<i32> = jvm.to_rust(list_instance)?;
1103 assert!(vec.len() == 10);
1104
1105 Ok(())
1106 }
1107
1108 #[test]
1109 fn basic_types() -> errors::Result<()> {
1110 let jvm = create_tests_jvm()?;
1111 let test_instance = jvm
1112 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1113 ?;
1114
1115 let arg = InvocationArg::try_from(33_i8)?;
1117 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1118 let ret: i8 = jvm.to_rust(i)?;
1119 assert!(ret == 33_i8);
1120
1121 let arg = InvocationArg::try_from(33_i16)?;
1122 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1123 let ret: i16 = jvm.to_rust(i)?;
1124 assert!(ret == 33_i16);
1125
1126 let arg = InvocationArg::try_from(33_i32)?;
1127 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1128 let ret: i32 = jvm.to_rust(i)?;
1129 assert!(ret == 33_i32);
1130
1131 let arg = InvocationArg::try_from(33_i64)?;
1132 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1133 let ret: i64 = jvm.to_rust(i)?;
1134 assert!(ret == 33_i64);
1135
1136 let arg = InvocationArg::try_from(33.33_f32)?;
1137 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1138 let ret: f32 = jvm.to_rust(i)?;
1139 assert!(ret == 33.33_f32);
1140
1141 let arg = InvocationArg::try_from(33.33_f64)?;
1142 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1143 let ret: f64 = jvm.to_rust(i)?;
1144 assert!(ret == 33.33_f64);
1145
1146 let arg = InvocationArg::try_from(&33_i8)?;
1148 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1149 let ret: i8 = jvm.to_rust(i)?;
1150 assert!(ret == 33_i8);
1151
1152 let arg = InvocationArg::try_from(&33_i16)?;
1153 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1154 let ret: i16 = jvm.to_rust(i)?;
1155 assert!(ret == 33_i16);
1156
1157 let arg = InvocationArg::try_from(&33_i32)?;
1158 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1159 let ret: i32 = jvm.to_rust(i)?;
1160 assert!(ret == 33_i32);
1161
1162 let arg = InvocationArg::try_from(&33_i64)?;
1163 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1164 let ret: i64 = jvm.to_rust(i)?;
1165 assert!(ret == 33_i64);
1166
1167 let arg = InvocationArg::try_from(&33.33_f32)?;
1168 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1169 let ret: f32 = jvm.to_rust(i)?;
1170 assert!(ret == 33.33_f32);
1171
1172 let arg = InvocationArg::try_from(&33.33_f64)?;
1173 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1174 let ret: f64 = jvm.to_rust(i)?;
1175 assert!(ret == 33.33_f64);
1176
1177 Ok(())
1178 }
1179
1180 #[test]
1181 fn vecs_arrays() -> errors::Result<()> {
1182 let jvm = create_tests_jvm()?;
1183 let test_instance = jvm
1184 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1185 ?;
1186
1187 let arg = InvocationArg::try_from([33_i8, 34_i8].as_slice())?;
1188 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1189 let ret: Vec<i8> = jvm.to_rust(i)?;
1190 assert!(ret == vec![33_i8, 34_i8]);
1191
1192 let arg = InvocationArg::try_from([33_i16, 34_i16].as_slice())?;
1193 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1194 let ret: Vec<i16> = jvm.to_rust(i)?;
1195 assert!(ret == vec![33_i16, 34_i16]);
1196
1197 let arg = InvocationArg::try_from([33_i32, 34_i32].as_slice())?;
1198 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1199 let ret: Vec<i32> = jvm.to_rust(i)?;
1200 assert!(ret == vec![33_i32, 34_i32]);
1201
1202 let arg = InvocationArg::try_from([33_i64, 34_i64].as_slice())?;
1203 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1204 let ret: Vec<i64> = jvm.to_rust(i)?;
1205 assert!(ret == vec![33_i64, 34_i64]);
1206
1207 let arg = InvocationArg::try_from([33_f32, 34_f32].as_slice())?;
1208 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1209 let ret: Vec<f32> = jvm.to_rust(i)?;
1210 assert!(ret == vec![33_f32, 34_f32]);
1211
1212 let arg = InvocationArg::try_from([33_f64, 34_f64].as_slice())?;
1213 let i = jvm.invoke(&test_instance, "echo", &[arg])?;
1214 let ret: Vec<f64> = jvm.to_rust(i)?;
1215 assert!(ret == vec![33_f64, 34_f64]);
1216
1217 Ok(())
1218 }
1219
1220 #[test]
1221 fn null_handling() -> errors::Result<()> {
1222 let jvm = create_tests_jvm()?;
1223 let test_instance = jvm
1224 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1225 ?;
1226 let null = jvm.invoke(&test_instance, "getNullInteger", InvocationArg::empty())?;
1227 let list_instance = jvm
1228 .invoke(
1229 &test_instance,
1230 "getNumbersUntil",
1231 &[InvocationArg::from(null)],
1232 )
1233 ?;
1234 let vec: Vec<i32> = jvm.to_rust(list_instance)?;
1235 assert!(vec.is_empty());
1236
1237 Ok(())
1238 }
1239
1240 #[test]
1241 fn null_creation() -> errors::Result<()> {
1242 let jvm = create_tests_jvm()?;
1243 let test_instance = jvm
1244 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1245 ?;
1246 let null = InvocationArg::try_from(Null::Of("java.lang.Integer"))?;
1247 let list_instance = jvm
1248 .invoke(&test_instance, "getNumbersUntil", &[null])
1249 ?;
1250 let vec: Vec<i32> = jvm.to_rust(list_instance)?;
1251 assert!(vec.is_empty());
1252
1253 let null = InvocationArg::try_from(Null::Integer)?;
1254 let list_instance = jvm
1255 .invoke(&test_instance, "getNumbersUntil", &[null])
1256 ?;
1257 let vec: Vec<i32> = jvm.to_rust(list_instance)?;
1258 assert!(vec.is_empty());
1259
1260 Ok(())
1261 }
1262
1263 #[test]
1264 fn to_rust_boxed() -> errors::Result<()> {
1265 let jvm = create_tests_jvm()?;
1266 let test_instance = jvm
1267 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1268 ?;
1269
1270 let i = jvm
1271 .invoke(
1272 &test_instance,
1273 "echo",
1274 &[InvocationArg::try_from(true)?],
1275 )
1276 ?;
1277 let _: Box<bool> = jvm.to_rust_boxed(i)?;
1278 let i = jvm
1279 .invoke(
1280 &test_instance,
1281 "echo",
1282 &[InvocationArg::try_from(33_i8)?],
1283 )
1284 ?;
1285 let _: Box<i8> = jvm.to_rust_boxed(i)?;
1286 let i = jvm
1287 .invoke(
1288 &test_instance,
1289 "echo",
1290 &[InvocationArg::try_from(33_i16)?],
1291 )
1292 ?;
1293 let _: Box<i16> = jvm.to_rust_boxed(i)?;
1294 let i = jvm
1295 .invoke(
1296 &test_instance,
1297 "echo",
1298 &[InvocationArg::try_from(33_i32)?],
1299 )
1300 ?;
1301 let _: Box<i32> = jvm.to_rust_boxed(i)?;
1302 let i = jvm
1303 .invoke(
1304 &test_instance,
1305 "echo",
1306 &[InvocationArg::try_from(33_i64)?],
1307 )
1308 ?;
1309 let _: Box<i64> = jvm.to_rust_boxed(i)?;
1310
1311 Ok(())
1312 }
1313
1314 #[test]
1315 fn check_equals() -> errors::Result<()> {
1316 let jvm = create_tests_jvm()?;
1317 let test_instance = jvm
1318 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1319 ?;
1320 let integer_instance = jvm.create_instance("java.lang.Integer", &[InvocationArg::try_from(3_i32)?.into_primitive()?])?;
1321 let ia1 = InvocationArg::try_from(3)?;
1322 assert!(jvm.check_equals(&integer_instance, &ia1)?);
1323
1324 let null_instance = jvm.invoke(&test_instance, "getNullInteger", InvocationArg::empty())?;
1325 assert!(jvm.check_equals(&null_instance, InvocationArg::try_from(Null::Integer)?)?);
1326 Ok(())
1327 }
1328
1329 #[test]
1330 fn instance_into_raw_object() -> errors::Result<()> {
1331 let jvm = create_tests_jvm()?;
1332 let test_instance = jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())?;
1333 let null_instance = jvm.invoke(&test_instance, "getNullInteger", InvocationArg::empty())?;
1334 let jobj = jvm.instance_into_raw_object(null_instance)?;
1335 assert!(jobj == null_mut());
1336 Ok(())
1337 }
1338
1339 #[test]
1340 fn jvm_into_raw_object() -> errors::Result<()> {
1341 let jvm = create_tests_jvm()?;
1342 let jobj = jvm.into_raw();
1343 assert!(jobj != null_mut());
1344 Ok(())
1345 }
1346}