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//! # j4rs
16//!
17//![![crates.io](https://img.shields.io/crates/v/j4rs.svg)](https://crates.io/crates/j4rs)
18//![![Maven Central](https://img.shields.io/badge/Maven%20Central-0.22.0-blue.svg)](https://central.sonatype.com/artifact/io.github.astonbitecode/j4rs/)
19//!![Build](https://github.com/astonbitecode/j4rs/actions/workflows/ci-workflow.yml/badge.svg)
20//!
21//!j4rs stands for __'Java for Rust'__ and allows effortless calls to Java code from Rust and vice-versa.
22//! 
23//! Please see the [README](https://github.com/astonbitecode/j4rs) for more details
24
25
26#[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
72/// Creates a new JVM, using the provided classpath entries and JVM arguments
73pub 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    // #[test]
344    // #[ignore]
345    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        // Create a MyTest instance
378        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        // Create two clones of the instance
384        let i1 = jvm.clone_instance(&i_arg)?;
385        let i2 = jvm.clone_instance(&i_arg)?;
386        // Use the clones as arguments
387        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    //    #[test]
402    //    #[ignore]
403    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    //        #[test]
428    //    #[ignore]
429    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    // #[test]
453    // #[ignore]
454    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    //    #[test]
483    //    #[ignore]
484    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    //    #[test]
512    //    #[ignore]
513    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                // Test using InvocationArgs
558                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                // Test using instances
568                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                // Test other types
576                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        // Create the MyTest instance
1010        let instance = jvm
1011            .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
1012            ?;
1013
1014        // Retrieve the annotated Map
1015        let dummy_map = jvm.invoke(&instance, "getMap", InvocationArg::empty())?;
1016
1017        // Put a new Map entry
1018        let _ = jvm
1019            .invoke(
1020                &dummy_map,
1021                "put",
1022                &[InvocationArg::try_from("three")?,
1023                    InvocationArg::try_from(3)?],
1024            )
1025            ?;
1026
1027        // Get the size of the new map and assert
1028        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        // Test the primitives in constructors.
1045        // The constructor of Integer takes a primitive int as an argument.
1046        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        // Test the primitives in invocations.
1054        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        // By values
1096        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        // By reference
1127        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}