dmsc/java/
converter.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! # Rust-Java Type Conversion
19//!
20//! Provides utilities for converting between Rust and Java types.
21
22use jni::JNIEnv;
23use jni::objects::{JObject, JString, JValue};
24use std::collections::HashMap;
25
26/// Trait for types that can be converted to Java objects
27pub trait ToJava {
28    fn to_java<'a>(&self, env: &mut JNIEnv<'a>) -> JObject<'a>;
29}
30
31/// Trait for types that can be converted from Java objects
32pub trait FromJava: Sized {
33    fn from_java<'a>(env: &mut JNIEnv<'a>, obj: JObject<'a>) -> Self;
34}
35
36/// Combined trait for bidirectional conversion
37pub trait JavaConvertible: ToJava + FromJava {}
38
39impl<T: ToJava + FromJava> JavaConvertible for T {}
40
41// String conversion
42impl 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
59// bool conversion
60impl 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
76// i32 conversion
77impl 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
93// i64 conversion
94impl 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
110// f64 conversion
111impl 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
127// Vec<String> conversion
128impl 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
173// HashMap<String, String> conversion
174impl 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
252/// Helper function to convert Option<T> to Java
253pub 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
260/// Helper function to convert Java object to Option<T>
261pub 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}