j4rs/api/
invocation_arg.rs

1// Copyright 2022 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
15use std::any::Any;
16use std::convert::TryFrom;
17use std::ptr;
18
19use jni_sys::{jobject, JNIEnv};
20use serde::Serialize;
21use serde_json;
22
23use crate::api::instance::Instance;
24use crate::api::{JavaClass, Jvm, Null};
25use crate::{cache, errors, jni_utils, utils};
26
27/// Struct that carries an argument that is used for method invocations in Java.
28#[derive(Serialize)]
29pub enum InvocationArg {
30    /// An arg that is created in the Java world.
31    Java {
32        instance: Instance,
33        class_name: String,
34        serialized: bool,
35    },
36    /// A serialized arg that is created in the Rust world.
37    Rust {
38        json: String,
39        class_name: String,
40        serialized: bool,
41    },
42    /// An non-serialized arg created in the Rust world, that contains a Java instance.
43    ///
44    /// The instance is a Basic Java type, like Integer, Float, String etc.
45    RustBasic {
46        instance: Instance,
47        class_name: String,
48        serialized: bool,
49    },
50}
51
52impl InvocationArg {
53
54    /// Return an empty slice of `InvocationArg`s
55    pub fn empty<'a>() -> &'a[InvocationArg;0] {
56        &[]
57    }
58
59    /// Creates a InvocationArg::Rust.
60    /// This is default for the Args that are created from the Rust code.
61    pub fn new<T>(arg: &T, class_name: &str) -> InvocationArg
62        where
63            T: Serialize + Any,
64    {
65        Self::new_2(
66            arg,
67            class_name,
68            cache::get_thread_local_env().expect("Could not find the jni_env in the local cache. Please make sure that you created a Jvm before using Jvm::new"))
69            .expect("Could not create the InvocationArg. Please see the logs/console for more details.")
70    }
71
72    pub fn new_2<T>(
73        arg: &T,
74        class_name: &str,
75        jni_env: *mut JNIEnv,
76    ) -> errors::Result<InvocationArg>
77        where
78            T: Serialize + Any,
79    {
80        let arg_any = arg as &dyn Any;
81        if let Some(a) = arg_any.downcast_ref::<String>() {
82            Ok(InvocationArg::RustBasic {
83                instance: Instance::new(
84                    jni_utils::global_jobject_from_str(a, jni_env)?,
85                    class_name,
86                )?,
87                class_name: class_name.to_string(),
88                serialized: false,
89            })
90        } else if let Some(a) = arg_any.downcast_ref::<i8>() {
91            Ok(InvocationArg::RustBasic {
92                instance: Instance::new(
93                    jni_utils::global_jobject_from_i8(a, jni_env)?,
94                    class_name,
95                )?,
96                class_name: class_name.to_string(),
97                serialized: false,
98            })
99        } else if let Some(a) = arg_any.downcast_ref::<i16>() {
100            Ok(InvocationArg::RustBasic {
101                instance: Instance::new(
102                    jni_utils::global_jobject_from_i16(a, jni_env)?,
103                    class_name,
104                )?,
105                class_name: class_name.to_string(),
106                serialized: false,
107            })
108        } else if let Some(a) = arg_any.downcast_ref::<i32>() {
109            Ok(InvocationArg::RustBasic {
110                instance: Instance::new(
111                    jni_utils::global_jobject_from_i32(a, jni_env)?,
112                    class_name,
113                )?,
114                class_name: class_name.to_string(),
115                serialized: false,
116            })
117        } else if let Some(a) = arg_any.downcast_ref::<i64>() {
118            Ok(InvocationArg::RustBasic {
119                instance: Instance::new(
120                    jni_utils::global_jobject_from_i64(a, jni_env)?,
121                    class_name,
122                )?,
123                class_name: class_name.to_string(),
124                serialized: false,
125            })
126        } else if let Some(a) = arg_any.downcast_ref::<f32>() {
127            Ok(InvocationArg::RustBasic {
128                instance: Instance::new(
129                    jni_utils::global_jobject_from_f32(a, jni_env)?,
130                    class_name,
131                )?,
132                class_name: class_name.to_string(),
133                serialized: false,
134            })
135        } else if let Some(a) = arg_any.downcast_ref::<f64>() {
136            Ok(InvocationArg::RustBasic {
137                instance: Instance::new(
138                    jni_utils::global_jobject_from_f64(a, jni_env)?,
139                    class_name,
140                )?,
141                class_name: class_name.to_string(),
142                serialized: false,
143            })
144        } else {
145            let json = serde_json::to_string(arg)?;
146            Ok(InvocationArg::Rust {
147                json: json,
148                class_name: class_name.to_string(),
149                serialized: true,
150            })
151        }
152    }
153
154    fn make_primitive(&mut self) -> errors::Result<()> {
155        match utils::primitive_of(self) {
156            Some(primitive_repr) => {
157                match self {
158                    &mut InvocationArg::Java {
159                        instance: _,
160                        ref mut class_name,
161                        serialized: _,
162                    } => *class_name = primitive_repr,
163                    &mut InvocationArg::Rust {
164                        json: _,
165                        ref mut class_name,
166                        serialized: _,
167                    } => *class_name = primitive_repr,
168                    &mut InvocationArg::RustBasic {
169                        instance: _,
170                        ref mut class_name,
171                        serialized: _,
172                    } => *class_name = primitive_repr,
173                };
174                Ok(())
175            }
176            None => Err(errors::J4RsError::JavaError(format!(
177                "Cannot transform to primitive: {}",
178                utils::get_class_name(&self)
179            ))),
180        }
181    }
182
183    /// Consumes this InvocationArg and transforms it to an InvocationArg that contains a Java primitive, leveraging Java's autoboxing.
184    ///
185    /// This action can be done by calling `Jvm::cast` of Instances as well (e.g.: jvm.cast(&instance, "int"))
186    /// but calling `into_primitive` is faster, as it does not involve JNI calls.
187    pub fn into_primitive(self) -> errors::Result<InvocationArg> {
188        let mut ia = self;
189        ia.make_primitive()?;
190        Ok(ia)
191    }
192
193    /// Creates a `jobject` from this InvocationArg.
194    pub fn as_java_ptr_with_global_ref(&self, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
195        match self {
196            _s @ &InvocationArg::Java { .. } => {
197                jni_utils::invocation_arg_jobject_from_java(&self, jni_env, true)
198            }
199            _s @ &InvocationArg::Rust { .. } => {
200                jni_utils::invocation_arg_jobject_from_rust_serialized(&self, jni_env, true)
201            }
202            _s @ &InvocationArg::RustBasic { .. } => {
203                jni_utils::invocation_arg_jobject_from_rust_basic(&self, jni_env, true)
204            }
205        }
206    }
207
208    /// Creates a `jobject` from this InvocationArg. The jobject contains a local reference.
209    pub fn as_java_ptr_with_local_ref(&self, jni_env: *mut JNIEnv) -> errors::Result<jobject> {
210        match self {
211            _s @ &InvocationArg::Java { .. } => {
212                jni_utils::invocation_arg_jobject_from_java(&self, jni_env, false)
213            }
214            _s @ &InvocationArg::Rust { .. } => {
215                jni_utils::invocation_arg_jobject_from_rust_serialized(&self, jni_env, false)
216            }
217            _s @ &InvocationArg::RustBasic { .. } => {
218                jni_utils::invocation_arg_jobject_from_rust_basic(&self, jni_env, false)
219            }
220        }
221    }
222
223    /// Consumes this invocation arg and returns its Instance
224    pub fn instance(self) -> errors::Result<Instance> {
225        match self {
226            InvocationArg::Java { instance: i, .. } => Ok(i),
227            InvocationArg::RustBasic { .. } => Err(errors::J4RsError::RustError(format!(
228                "Invalid operation: Cannot get the instance of an InvocationArg::RustBasic"
229            ))),
230            InvocationArg::Rust { .. } => Err(errors::J4RsError::RustError(format!(
231                "Cannot get the instance from an InvocationArg::Rust"
232            ))),
233        }
234    }
235
236    pub fn class_name(&self) -> &str {
237        match self {
238            &InvocationArg::Java {
239                instance: _,
240                ref class_name,
241                serialized: _,
242            } => class_name,
243            &InvocationArg::Rust {
244                json: _,
245                ref class_name,
246                serialized: _,
247            } => class_name,
248            &InvocationArg::RustBasic {
249                instance: _,
250                ref class_name,
251                serialized: _,
252            } => class_name,
253        }
254    }
255
256    /// Creates an InvocationArg that contains null
257    pub fn create_null(null: Null) -> errors::Result<InvocationArg> {
258        let class_name: &str = match null {
259            Null::String => JavaClass::String,
260            Null::Boolean => JavaClass::Boolean,
261            Null::Byte => JavaClass::Byte,
262            Null::Character => JavaClass::Character,
263            Null::Short => JavaClass::Short,
264            Null::Integer => JavaClass::Integer,
265            Null::Long => JavaClass::Long,
266            Null::Float => JavaClass::Float,
267            Null::Double => JavaClass::Double,
268            Null::List => JavaClass::List,
269            Null::Of(class_name) => JavaClass::Of(class_name),
270        }
271            .into();
272        Ok(InvocationArg::RustBasic {
273            instance: Instance::new(ptr::null_mut(), class_name)?,
274            class_name: class_name.to_string(),
275            serialized: false,
276        })
277    }
278}
279
280impl From<Instance> for InvocationArg {
281    fn from(instance: Instance) -> InvocationArg {
282        let class_name = instance.class_name.to_owned();
283
284        InvocationArg::Java {
285            instance: instance,
286            class_name: class_name,
287            serialized: false,
288        }
289    }
290}
291
292impl TryFrom<Result<Instance, errors::J4RsError>> for InvocationArg {
293    type Error = errors::J4RsError;
294
295    fn try_from(
296        instance_res: Result<Instance, errors::J4RsError>,
297    ) -> errors::Result<InvocationArg> {
298        Ok(InvocationArg::from(instance_res?))
299    }
300}
301
302impl<'a> TryFrom<Null<'a>> for InvocationArg {
303    type Error = errors::J4RsError;
304    fn try_from(null: Null) -> errors::Result<InvocationArg> {
305        InvocationArg::create_null(null)
306    }
307}
308
309impl TryFrom<String> for InvocationArg {
310    type Error = errors::J4RsError;
311    fn try_from(arg: String) -> errors::Result<InvocationArg> {
312        InvocationArg::new_2(
313            &arg,
314            JavaClass::String.into(),
315            cache::get_thread_local_env()?,
316        )
317    }
318}
319
320impl<'a> TryFrom<&'a [String]> for InvocationArg {
321    type Error = errors::J4RsError;
322    fn try_from(vec: &'a [String]) -> errors::Result<InvocationArg> {
323        let args: errors::Result<Vec<InvocationArg>> = vec
324            .iter()
325            .map(|elem| InvocationArg::try_from(elem))
326            .collect();
327        let res =
328            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
329        Ok(InvocationArg::from(res?))
330    }
331}
332
333impl<'a> TryFrom<&'a str> for InvocationArg {
334    type Error = errors::J4RsError;
335    fn try_from(arg: &'a str) -> errors::Result<InvocationArg> {
336        InvocationArg::new_2(
337            &arg.to_string(),
338            JavaClass::String.into(),
339            cache::get_thread_local_env()?,
340        )
341    }
342}
343
344impl<'a> TryFrom<&'a [&'a str]> for InvocationArg {
345    type Error = errors::J4RsError;
346    fn try_from(vec: &'a [&'a str]) -> errors::Result<InvocationArg> {
347        let args: errors::Result<Vec<InvocationArg>> = vec
348            .iter()
349            .map(|&elem| InvocationArg::try_from(elem))
350            .collect();
351        let res =
352            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
353        Ok(InvocationArg::from(res?))
354    }
355}
356
357impl TryFrom<bool> for InvocationArg {
358    type Error = errors::J4RsError;
359    fn try_from(arg: bool) -> errors::Result<InvocationArg> {
360        InvocationArg::new_2(
361            &arg,
362            JavaClass::Boolean.into(),
363            cache::get_thread_local_env()?,
364        )
365    }
366}
367
368impl<'a> TryFrom<&'a [bool]> for InvocationArg {
369    type Error = errors::J4RsError;
370    fn try_from(vec: &'a [bool]) -> errors::Result<InvocationArg> {
371        let args: errors::Result<Vec<InvocationArg>> = vec
372            .iter()
373            .map(|elem| InvocationArg::try_from(elem))
374            .collect();
375        let res =
376            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
377        Ok(InvocationArg::from(res?))
378    }
379}
380
381impl TryFrom<i8> for InvocationArg {
382    type Error = errors::J4RsError;
383    fn try_from(arg: i8) -> errors::Result<InvocationArg> {
384        InvocationArg::new_2(&arg, JavaClass::Byte.into(), cache::get_thread_local_env()?)
385    }
386}
387
388impl<'a> TryFrom<&'a [i8]> for InvocationArg {
389    type Error = errors::J4RsError;
390    fn try_from(vec: &'a [i8]) -> errors::Result<InvocationArg> {
391        let args: errors::Result<Vec<InvocationArg>> = vec
392            .iter()
393            .map(|elem| InvocationArg::try_from(elem))
394            .collect();
395        let res =
396            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
397        Ok(InvocationArg::from(res?))
398    }
399}
400
401impl TryFrom<char> for InvocationArg {
402    type Error = errors::J4RsError;
403    fn try_from(arg: char) -> errors::Result<InvocationArg> {
404        InvocationArg::new_2(
405            &arg,
406            JavaClass::Character.into(),
407            cache::get_thread_local_env()?,
408        )
409    }
410}
411
412impl<'a> TryFrom<&'a [char]> for InvocationArg {
413    type Error = errors::J4RsError;
414    fn try_from(vec: &'a [char]) -> errors::Result<InvocationArg> {
415        let args: errors::Result<Vec<InvocationArg>> = vec
416            .iter()
417            .map(|elem| InvocationArg::try_from(elem))
418            .collect();
419        let res =
420            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
421        Ok(InvocationArg::from(res?))
422    }
423}
424
425impl TryFrom<i16> for InvocationArg {
426    type Error = errors::J4RsError;
427    fn try_from(arg: i16) -> errors::Result<InvocationArg> {
428        InvocationArg::new_2(
429            &arg,
430            JavaClass::Short.into(),
431            cache::get_thread_local_env()?,
432        )
433    }
434}
435
436impl<'a> TryFrom<&'a [i16]> for InvocationArg {
437    type Error = errors::J4RsError;
438    fn try_from(vec: &'a [i16]) -> errors::Result<InvocationArg> {
439        let args: errors::Result<Vec<InvocationArg>> = vec
440            .iter()
441            .map(|elem| InvocationArg::try_from(elem))
442            .collect();
443        let res =
444            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
445        Ok(InvocationArg::from(res?))
446    }
447}
448
449impl TryFrom<i32> for InvocationArg {
450    type Error = errors::J4RsError;
451    fn try_from(arg: i32) -> errors::Result<InvocationArg> {
452        InvocationArg::new_2(
453            &arg,
454            JavaClass::Integer.into(),
455            cache::get_thread_local_env()?,
456        )
457    }
458}
459
460impl<'a> TryFrom<&'a [i32]> for InvocationArg {
461    type Error = errors::J4RsError;
462    fn try_from(vec: &'a [i32]) -> errors::Result<InvocationArg> {
463        let args: errors::Result<Vec<InvocationArg>> = vec
464            .iter()
465            .map(|elem| InvocationArg::try_from(elem))
466            .collect();
467        let res =
468            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
469        Ok(InvocationArg::from(res?))
470    }
471}
472
473impl TryFrom<i64> for InvocationArg {
474    type Error = errors::J4RsError;
475    fn try_from(arg: i64) -> errors::Result<InvocationArg> {
476        InvocationArg::new_2(&arg, JavaClass::Long.into(), cache::get_thread_local_env()?)
477    }
478}
479
480impl<'a> TryFrom<&'a [i64]> for InvocationArg {
481    type Error = errors::J4RsError;
482    fn try_from(vec: &'a [i64]) -> errors::Result<InvocationArg> {
483        let args: errors::Result<Vec<InvocationArg>> = vec
484            .iter()
485            .map(|elem| InvocationArg::try_from(elem))
486            .collect();
487        let res =
488            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
489        Ok(InvocationArg::from(res?))
490    }
491}
492
493impl TryFrom<f32> for InvocationArg {
494    type Error = errors::J4RsError;
495    fn try_from(arg: f32) -> errors::Result<InvocationArg> {
496        InvocationArg::new_2(
497            &arg,
498            JavaClass::Float.into(),
499            cache::get_thread_local_env()?,
500        )
501    }
502}
503
504impl<'a> TryFrom<&'a [f32]> for InvocationArg {
505    type Error = errors::J4RsError;
506    fn try_from(vec: &'a [f32]) -> errors::Result<InvocationArg> {
507        let args: errors::Result<Vec<InvocationArg>> = vec
508            .iter()
509            .map(|elem| InvocationArg::try_from(elem))
510            .collect();
511        let res =
512            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
513        Ok(InvocationArg::from(res?))
514    }
515}
516
517impl TryFrom<f64> for InvocationArg {
518    type Error = errors::J4RsError;
519    fn try_from(arg: f64) -> errors::Result<InvocationArg> {
520        InvocationArg::new_2(
521            &arg,
522            JavaClass::Double.into(),
523            cache::get_thread_local_env()?,
524        )
525    }
526}
527
528impl<'a> TryFrom<&'a [f64]> for InvocationArg {
529    type Error = errors::J4RsError;
530    fn try_from(vec: &'a [f64]) -> errors::Result<InvocationArg> {
531        let args: errors::Result<Vec<InvocationArg>> = vec
532            .iter()
533            .map(|elem| InvocationArg::try_from(elem))
534            .collect();
535        let res =
536            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
537        Ok(InvocationArg::from(res?))
538    }
539}
540
541impl TryFrom<()> for InvocationArg {
542    type Error = errors::J4RsError;
543    fn try_from(arg: ()) -> errors::Result<InvocationArg> {
544        InvocationArg::new_2(&arg, JavaClass::Void.into(), cache::get_thread_local_env()?)
545    }
546}
547
548impl<'a> TryFrom<&'a String> for InvocationArg {
549    type Error = errors::J4RsError;
550    fn try_from(arg: &'a String) -> errors::Result<InvocationArg> {
551        InvocationArg::new_2(
552            arg,
553            JavaClass::String.into(),
554            cache::get_thread_local_env()?,
555        )
556    }
557}
558
559impl<'a> TryFrom<&'a bool> for InvocationArg {
560    type Error = errors::J4RsError;
561    fn try_from(arg: &'a bool) -> errors::Result<InvocationArg> {
562        InvocationArg::new_2(
563            arg,
564            JavaClass::Boolean.into(),
565            cache::get_thread_local_env()?,
566        )
567    }
568}
569
570impl<'a> TryFrom<&'a i8> for InvocationArg {
571    type Error = errors::J4RsError;
572    fn try_from(arg: &'a i8) -> errors::Result<InvocationArg> {
573        InvocationArg::new_2(arg, JavaClass::Byte.into(), cache::get_thread_local_env()?)
574    }
575}
576
577impl<'a> TryFrom<&'a char> for InvocationArg {
578    type Error = errors::J4RsError;
579    fn try_from(arg: &'a char) -> errors::Result<InvocationArg> {
580        InvocationArg::new_2(
581            arg,
582            JavaClass::Character.into(),
583            cache::get_thread_local_env()?,
584        )
585    }
586}
587
588impl<'a> TryFrom<&'a i16> for InvocationArg {
589    type Error = errors::J4RsError;
590    fn try_from(arg: &'a i16) -> errors::Result<InvocationArg> {
591        InvocationArg::new_2(arg, JavaClass::Short.into(), cache::get_thread_local_env()?)
592    }
593}
594
595impl<'a, 'b> TryFrom<&'a i32> for InvocationArg {
596    type Error = errors::J4RsError;
597    fn try_from(arg: &'a i32) -> errors::Result<InvocationArg> {
598        InvocationArg::new_2(
599            arg,
600            JavaClass::Integer.into(),
601            cache::get_thread_local_env()?,
602        )
603    }
604}
605
606impl<'a> TryFrom<&'a i64> for InvocationArg {
607    type Error = errors::J4RsError;
608    fn try_from(arg: &'a i64) -> errors::Result<InvocationArg> {
609        InvocationArg::new_2(arg, JavaClass::Long.into(), cache::get_thread_local_env()?)
610    }
611}
612
613impl<'a> TryFrom<&'a f32> for InvocationArg {
614    type Error = errors::J4RsError;
615    fn try_from(arg: &'a f32) -> errors::Result<InvocationArg> {
616        InvocationArg::new_2(arg, JavaClass::Float.into(), cache::get_thread_local_env()?)
617    }
618}
619
620impl<'a> TryFrom<&'a f64> for InvocationArg {
621    type Error = errors::J4RsError;
622    fn try_from(arg: &'a f64) -> errors::Result<InvocationArg> {
623        InvocationArg::new_2(
624            arg,
625            JavaClass::Double.into(),
626            cache::get_thread_local_env()?,
627        )
628    }
629}
630
631impl<'a, T: 'static> TryFrom<(&'a [T], &'a str)> for InvocationArg
632    where
633        T: Serialize,
634{
635    type Error = errors::J4RsError;
636    fn try_from(vec: (&'a [T], &'a str)) -> errors::Result<InvocationArg> {
637        let (vec, elements_class_name) = vec;
638        let jni_env = cache::get_thread_local_env()?;
639        let args: errors::Result<Vec<InvocationArg>> = vec
640            .iter()
641            .map(|elem| {
642                InvocationArg::new_2(elem, JavaClass::Of(elements_class_name).into(), jni_env)
643            })
644            .collect();
645        let res =
646            Jvm::do_create_java_list(cache::get_thread_local_env()?, cache::J4RS_ARRAY, &args?);
647        Ok(InvocationArg::from(res?))
648    }
649}
650
651impl TryFrom<Result<InvocationArg, errors::J4RsError>> for InvocationArg {
652    type Error = errors::J4RsError;
653    fn try_from(arg: Result<InvocationArg, errors::J4RsError>) -> errors::Result<InvocationArg> {
654        arg
655    }
656}
657
658#[cfg(test)]
659mod inv_arg_unit_tests {
660    use serde::Deserialize;
661
662    use crate::{api, errors, JvmBuilder, MavenArtifact};
663
664    use super::*;
665
666    fn create_tests_jvm() -> errors::Result<Jvm> {
667        let jvm: Jvm = JvmBuilder::new().build()?;
668        jvm.deploy_artifact(&MavenArtifact::from(format!("io.github.astonbitecode:j4rs-testing:{}", api::j4rs_version()).as_str()))?;
669        Ok(jvm)
670    }
671
672    #[test]
673    fn new_invocation_arg() -> errors::Result<()> {
674        let _jvm = create_tests_jvm()?;
675        let _ = InvocationArg::new(&"something".to_string(), "somethingelse");
676
677        Ok(())
678    }
679
680    #[test]
681    fn invocation_arg_try_from_basic_types() -> errors::Result<()> {
682        let _jvm = create_tests_jvm()?;
683        validate_type(InvocationArg::try_from("str")?, "java.lang.String");
684        validate_type(
685            InvocationArg::try_from("str".to_string())?,
686            "java.lang.String",
687        );
688        validate_type(InvocationArg::try_from(true)?, "java.lang.Boolean");
689        validate_type(InvocationArg::try_from(1_i8)?, "java.lang.Byte");
690        validate_type(InvocationArg::try_from('c')?, "java.lang.Character");
691        validate_type(InvocationArg::try_from(1_i16)?, "java.lang.Short");
692        validate_type(InvocationArg::try_from(1_i64)?, "java.lang.Long");
693        validate_type(InvocationArg::try_from(0.1_f32)?, "java.lang.Float");
694        validate_type(
695            InvocationArg::try_from(0.1_f64)?,
696            "java.lang.Double",
697        );
698        validate_type(InvocationArg::try_from(())?, "void");
699
700        validate_type(
701            InvocationArg::try_from(&"str".to_string())?,
702            "java.lang.String",
703        );
704        validate_type(InvocationArg::try_from("str")?, "java.lang.String");
705        validate_type(InvocationArg::try_from(&true)?, "java.lang.Boolean");
706        validate_type(InvocationArg::try_from(&1_i8)?, "java.lang.Byte");
707        validate_type(
708            InvocationArg::try_from(&'c')?,
709            "java.lang.Character",
710        );
711        validate_type(InvocationArg::try_from(&1_i16)?, "java.lang.Short");
712        validate_type(InvocationArg::try_from(&1_i64)?, "java.lang.Long");
713        validate_type(
714            InvocationArg::try_from(&0.1_f32)?,
715            "java.lang.Float",
716        );
717        validate_type(
718            InvocationArg::try_from(&0.1_f64)?,
719            "java.lang.Double",
720        );
721
722        Ok(())
723    }
724
725    #[test]
726    fn invocation_into_primitive() -> errors::Result<()> {
727        let _jvm: Jvm = create_tests_jvm()?;
728        assert!(InvocationArg::try_from(false)?
729            .into_primitive()
730            .is_ok());
731        assert!(InvocationArg::try_from(1_i8)?
732            .into_primitive()
733            .is_ok());
734        assert!(InvocationArg::try_from(1_i16)?
735            .into_primitive()
736            .is_ok());
737        assert!(InvocationArg::try_from(1_i32)?
738            .into_primitive()
739            .is_ok());
740        assert!(InvocationArg::try_from(1_i64)?
741            .into_primitive()
742            .is_ok());
743        assert!(InvocationArg::try_from(0.1_f32)?
744            .into_primitive()
745            .is_ok());
746        assert!(InvocationArg::try_from(0.1_f64)?
747            .into_primitive()
748            .is_ok());
749        assert!(InvocationArg::try_from('c')?
750            .into_primitive()
751            .is_ok());
752        assert!(InvocationArg::try_from(())?
753            .into_primitive()
754            .is_ok());
755        assert!(InvocationArg::try_from("string")?
756            .into_primitive()
757            .is_err());
758
759        Ok(())
760    }
761
762    #[test]
763    fn invocation_arg_for_custom_types() -> errors::Result<()> {
764        let jvm = create_tests_jvm()?;
765
766        let my_bean = MyBean {
767            someString: "My String In A Bean".to_string(),
768            someInteger: 33,
769        };
770        let ia = InvocationArg::new(&my_bean, "org.astonbitecode.j4rs.tests.MyBean");
771
772        let test_instance = jvm.create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())?;
773        let string_instance = jvm.invoke(&test_instance, "getTheString", &[ia]).unwrap();
774
775        let rust_string: String = jvm.to_rust(string_instance).unwrap();
776
777        assert!(&rust_string == "My String In A Bean");
778
779        Ok(())
780    }
781
782    #[derive(Serialize, Deserialize, Debug)]
783    #[allow(non_snake_case)]
784    struct MyBean {
785        someString: String,
786        someInteger: isize,
787    }
788
789    fn validate_type(ia: InvocationArg, class: &str) {
790        let b = match ia {
791            _s @ InvocationArg::Java { .. } => false,
792            InvocationArg::Rust {
793                class_name,
794                json: _,
795                ..
796            } => class == class_name,
797            InvocationArg::RustBasic {
798                instance: _,
799                class_name,
800                serialized: _,
801            } => class == class_name,
802        };
803        assert!(b);
804    }
805}