1use jni::JNIEnv;
23use jni::objects::{JObject, JString, JValue};
24use std::collections::HashMap;
25
26pub trait ToJava {
28 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a>;
29}
30
31pub trait FromJava: Sized {
33 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self;
34}
35
36pub trait JavaConvertible: ToJava + FromJava {}
38
39impl<T: ToJava + FromJava> JavaConvertible for T {}
40
41impl ToJava for String {
43 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a> {
44 env.new_string(self)
45 .expect("Failed to create Java string")
46 .into()
47 }
48}
49
50impl FromJava for String {
51 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self {
52 let jstr: JString = obj.into();
53 env.get_string(&jstr)
54 .expect("Failed to get Rust string")
55 .into()
56 }
57}
58
59impl ToJava for bool {
61 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a> {
62 env.new_object("java/lang/Boolean", "(Z)V", &[JValue::Bool(*self as u8)])
63 .expect("Failed to create Java Boolean")
64 }
65}
66
67impl FromJava for bool {
68 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self {
69 env.call_method(&obj, "booleanValue", "()Z", &[])
70 .expect("Failed to call booleanValue")
71 .z()
72 .expect("Failed to get boolean value")
73 }
74}
75
76impl ToJava for i32 {
78 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a> {
79 env.new_object("java/lang/Integer", "(I)V", &[JValue::Int(*self)])
80 .expect("Failed to create Java Integer")
81 }
82}
83
84impl FromJava for i32 {
85 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self {
86 env.call_method(&obj, "intValue", "()I", &[])
87 .expect("Failed to call intValue")
88 .i()
89 .expect("Failed to get int value")
90 }
91}
92
93impl ToJava for i64 {
95 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a> {
96 env.new_object("java/lang/Long", "(J)V", &[JValue::Long(*self)])
97 .expect("Failed to create Java Long")
98 }
99}
100
101impl FromJava for i64 {
102 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self {
103 env.call_method(&obj, "longValue", "()J", &[])
104 .expect("Failed to call longValue")
105 .j()
106 .expect("Failed to get long value")
107 }
108}
109
110impl ToJava for f64 {
112 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a> {
113 env.new_object("java/lang/Double", "(D)V", &[JValue::Double(*self)])
114 .expect("Failed to create Java Double")
115 }
116}
117
118impl FromJava for f64 {
119 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self {
120 env.call_method(&obj, "doubleValue", "()D", &[])
121 .expect("Failed to call doubleValue")
122 .d()
123 .expect("Failed to get double value")
124 }
125}
126
127impl ToJava for Vec<String> {
129 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a> {
130 let list = env
131 .new_object("java/util/ArrayList", "()V", &[])
132 .expect("Failed to create ArrayList");
133
134 for item in self {
135 let jitem = item.to_java(env);
136 env.call_method(
137 &list,
138 "add",
139 "(Ljava/lang/Object;)Z",
140 &[JValue::Object(&jitem)],
141 )
142 .expect("Failed to add item to list");
143 }
144
145 list
146 }
147}
148
149impl FromJava for Vec<String> {
150 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self {
151 let size = env
152 .call_method(&obj, "size", "()I", &[])
153 .expect("Failed to get list size")
154 .i()
155 .expect("Failed to get size value") as usize;
156
157 let mut result = Vec::with_capacity(size);
158
159 for i in 0..size {
160 let item = env
161 .call_method(&obj, "get", "(I)Ljava/lang/Object;", &[JValue::Int(i as i32)])
162 .expect("Failed to get list item")
163 .l()
164 .expect("Failed to get object");
165
166 result.push(String::from_java(env, item));
167 }
168
169 result
170 }
171}
172
173impl ToJava for HashMap<String, String> {
175 fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a> {
176 let map = env
177 .new_object("java/util/HashMap", "()V", &[])
178 .expect("Failed to create HashMap");
179
180 for (key, value) in self {
181 let jkey = key.to_java(env);
182 let jvalue = value.to_java(env);
183
184 env.call_method(
185 &map,
186 "put",
187 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
188 &[JValue::Object(&jkey), JValue::Object(&jvalue)],
189 )
190 .expect("Failed to put entry in map");
191 }
192
193 map
194 }
195}
196
197impl FromJava for HashMap<String, String> {
198 fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self {
199 let entry_set = env
200 .call_method(&obj, "entrySet", "()Ljava/util/Set;", &[])
201 .expect("Failed to get entry set")
202 .l()
203 .expect("Failed to get set object");
204
205 let iterator = env
206 .call_method(&entry_set, "iterator", "()Ljava/util/Iterator;", &[])
207 .expect("Failed to get iterator")
208 .l()
209 .expect("Failed to get iterator object");
210
211 let mut result = HashMap::new();
212
213 loop {
214 let has_next = env
215 .call_method(&iterator, "hasNext", "()Z", &[])
216 .expect("Failed to call hasNext")
217 .z()
218 .expect("Failed to get boolean");
219
220 if !has_next {
221 break;
222 }
223
224 let entry = env
225 .call_method(&iterator, "next", "()Ljava/lang/Object;", &[])
226 .expect("Failed to get next entry")
227 .l()
228 .expect("Failed to get entry object");
229
230 let jkey = env
231 .call_method(&entry, "getKey", "()Ljava/lang/Object;", &[])
232 .expect("Failed to get key")
233 .l()
234 .expect("Failed to get key object");
235
236 let jvalue = env
237 .call_method(&entry, "getValue", "()Ljava/lang/Object;", &[])
238 .expect("Failed to get value")
239 .l()
240 .expect("Failed to get value object");
241
242 let key = String::from_java(env, jkey);
243 let value = String::from_java(env, jvalue);
244
245 result.insert(key, value);
246 }
247
248 result
249 }
250}
251
252pub fn option_to_java<'a, T: ToJava>(env: &mut JNIEnv<'a>, opt: &Option<T>) -> JObject<'a> {
254 match opt {
255 Some(value) => value.to_java(env),
256 None => JObject::null(),
257 }
258}
259
260pub fn option_from_java<'a, T: FromJava>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Option<T> {
262 if obj.is_null() {
263 None
264 } else {
265 Some(T::from_java(env, obj))
266 }
267}