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