j4rs/
lib.rs

1// Copyright 2018 astonbitecode
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#[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
61/// Creates a new JVM, using the provided classpath entries and JVM arguments
62pub 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    // #[test]
328    // #[ignore]
329    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        // Create a MyTest instance
362        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        // Create two clones of the instance
368        let i1 = jvm.clone_instance(&i_arg)?;
369        let i2 = jvm.clone_instance(&i_arg)?;
370        // Use the clones as arguments
371        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    //    #[test]
386    //    #[ignore]
387    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    //        #[test]
412    //    #[ignore]
413    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    // #[test]
437    // #[ignore]
438    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    //    #[test]
467    //    #[ignore]
468    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    //    #[test]
496    //    #[ignore]
497    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                // Test using InvocationArgs
542                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                // Test using instances
552                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                // Test other types
560                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        // Create the MyTest instance
994        let instance = jvm
995            .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
996            ?;
997
998        // Retrieve the annotated Map
999        let dummy_map = jvm.invoke(&instance, "getMap", InvocationArg::empty())?;
1000
1001        // Put a new Map entry
1002        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        // Get the size of the new map and assert
1014        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        // Test the primitives in constructors.
1031        // The constructor of Integer takes a primitive int as an argument.
1032        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        // Test the primitives in invocations.
1040        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        // By values
1082        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        // By reference
1113        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}