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