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