jni_toolbox/
into_java.rs

1use jni::objects::JObject;
2
3
4/// Specifies how a Rust type should be converted into a Java primitive.
5pub trait IntoJava<'j> {
6	/// The JNI type representing the output.
7	type Ret;
8	/// Attempts to convert this Rust object into a Java primitive.
9	fn into_java(self, _: &mut jni::JNIEnv<'j>) -> Result<Self::Ret, jni::errors::Error>;
10}
11
12macro_rules! auto_into_java {
13	($t: ty, $j: ty) => {
14		impl<'j> IntoJava<'j> for $t {
15			type Ret = $j;
16		
17			#[inline]
18			fn into_java(self, _: &mut jni::JNIEnv<'j>) -> Result<Self::Ret, jni::errors::Error> {
19				Ok(self)
20			}
21		}
22	};
23}
24
25// TODO: primitive arrays!
26
27auto_into_java!(i64, jni::sys::jlong);
28auto_into_java!(i32, jni::sys::jint);
29auto_into_java!(i16, jni::sys::jshort);
30auto_into_java!(i8, jni::sys::jbyte);
31auto_into_java!(f32, jni::sys::jfloat);
32auto_into_java!(f64, jni::sys::jdouble);
33auto_into_java!((), ());
34
35impl<'j> IntoJava<'j> for bool {
36	type Ret = jni::sys::jboolean;
37
38	#[inline]
39	fn into_java(self, _: &mut jni::JNIEnv) -> Result<Self::Ret, jni::errors::Error> {
40		Ok(if self { 1 } else { 0 })
41	}
42}
43
44impl<'j, X: IntoJavaObject<'j>> IntoJava<'j> for X {
45	type Ret = jni::sys::jobject;
46
47	#[inline]
48	fn into_java(self, env: &mut jni::JNIEnv<'j>) -> Result<Self::Ret, jni::errors::Error> {
49		Ok(self.into_java_object(env)?.as_raw())
50	}
51}
52
53/// Specifies how a Rust type should be converted into a Java object.
54pub trait IntoJavaObject<'j> {
55	/// The Java class associated with this type.
56	const CLASS: &'static str;
57	/// Attempts to convert this Rust object into a Java object.
58	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error>;
59}
60
61impl<'j> IntoJavaObject<'j> for JObject<'j> {
62	const CLASS: &'static str = "java/lang/Object";
63	#[inline]
64	fn into_java_object(self, _: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
65		Ok(self)
66	}
67}
68
69macro_rules! auto_into_java_object {
70	($t:ty, $cls:literal) => {
71		impl<'j> IntoJavaObject<'j> for $t {
72			const CLASS: &'static str = $cls;
73			#[inline]
74			fn into_java_object(self, _: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
75				Ok(self.into())
76			}
77		}
78	};
79}
80
81auto_into_java_object!(jni::objects::JString<'j>, "java/lang/String");
82auto_into_java_object!(jni::objects::JObjectArray<'j>, "java/lang/Object[]");
83auto_into_java_object!(jni::objects::JIntArray<'j>, "java/lang/Integer[]");
84auto_into_java_object!(jni::objects::JLongArray<'j>, "java/lang/Long[]");
85auto_into_java_object!(jni::objects::JShortArray<'j>, "java/lang/Short[]");
86auto_into_java_object!(jni::objects::JByteArray<'j>, "java/lang/Byte[]");
87auto_into_java_object!(jni::objects::JCharArray<'j>, "java/lang/Char[]");
88auto_into_java_object!(jni::objects::JFloatArray<'j>, "java/lang/Float[]");
89auto_into_java_object!(jni::objects::JDoubleArray<'j>, "java/lang/Double[]");
90auto_into_java_object!(jni::objects::JBooleanArray<'j>, "java/lang/Boolean[]");
91
92
93impl<'j> IntoJavaObject<'j> for &str {
94	const CLASS: &'static str = "java/lang/String";
95	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
96		Ok(env.new_string(self)?.into())
97	}
98}
99
100impl<'j> IntoJavaObject<'j> for String {
101	const CLASS: &'static str = "java/lang/String";
102	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
103		self.as_str().into_java_object(env)
104	}
105}
106
107impl<'j, T: IntoJavaObject<'j>> IntoJavaObject<'j> for Vec<T> {
108	const CLASS: &'static str = T::CLASS; // TODO shouldnt it be 'Object[]' ?
109	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
110		let mut array = env.new_object_array(self.len() as i32, T::CLASS, JObject::null())?;
111		for (n, el) in self.into_iter().enumerate() {
112			let el = el.into_java_object(env)?;
113			env.set_object_array_element(&mut array, n as i32, &el)?;
114		}
115		Ok(array.into())
116	}
117}
118
119impl<'j, T: IntoJavaObject<'j>> IntoJavaObject<'j> for Option<T> {
120	const CLASS: &'static str = T::CLASS;
121	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
122		match self {
123			Some(x) => x.into_java_object(env),
124			None => Ok(JObject::null())
125		}
126	}
127}
128
129macro_rules! auto_into_java_object_primitive_array {
130	($t:ty, $fn_new:ident, $fn_set:ident, $clazz:literal) => {
131		impl<'j> IntoJavaObject<'j> for Vec<$t> {
132			const CLASS: &'static str = $clazz;
133			fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
134				let len = self.len()
135					.try_into()
136					.map_err(|_| jni::errors::Error::JniCall(jni::errors::JniError::InvalidArguments))?;
137				let mut array = env.$fn_new(len)?;
138				env.$fn_set(&mut array, 0, self.as_slice())?;
139				Ok(array.into())
140			}
141		}
142	};
143}
144
145auto_into_java_object_primitive_array!(i8, new_byte_array, set_byte_array_region, "java/lang/Byte[]");
146auto_into_java_object_primitive_array!(i16, new_short_array, set_short_array_region, "java/lang/Short[]");
147auto_into_java_object_primitive_array!(i32, new_int_array, set_int_array_region, "java/lang/Integer[]");
148auto_into_java_object_primitive_array!(i64, new_long_array, set_long_array_region, "java/lang/Long[]");
149auto_into_java_object_primitive_array!(f32, new_float_array, set_float_array_region, "java/lang/Float[]");
150auto_into_java_object_primitive_array!(f64, new_double_array, set_double_array_region, "java/lang/Double[]");
151
152impl<'j> IntoJavaObject<'j> for Vec<bool> {
153	const CLASS: &'static str = "java/lang/Boolean[]";
154
155	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
156		let len = self.len()
157			.try_into()
158			.map_err(|_| jni::errors::Error::JniCall(jni::errors::JniError::InvalidArguments))?;
159		let mut array = env.new_boolean_array(len)?;
160		let new_self : Vec<u8> = self.into_iter().map(|x| if x { 1 } else { 0 }).collect();
161		env.set_boolean_array_region(&mut array, 0, new_self.as_slice())?;
162		Ok(array.into())
163	}
164}
165
166impl<'j> IntoJavaObject<'j> for Vec<char> {
167	const CLASS: &'static str = "java/lang/Char[]";
168
169	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
170		let len = self.len()
171			.try_into()
172			.map_err(|_| jni::errors::Error::JniCall(jni::errors::JniError::InvalidArguments))?;
173		let mut array = env.new_char_array(len)?;
174		let mut new_self : Vec<u16> = Vec::new();
175		for c in self {
176			new_self.push(
177				c
178					.try_into()
179					.map_err(|_| jni::errors::Error::JniCall(jni::errors::JniError::InvalidArguments))?
180			);
181		}
182		env.set_char_array_region(&mut array, 0, new_self.as_slice())?;
183		Ok(array.into())
184	}
185}
186
187#[cfg(feature = "uuid")]
188impl<'j> IntoJavaObject<'j> for uuid::Uuid {
189	const CLASS: &'static str = "java/util/UUID";
190	fn into_java_object(self, env: &mut jni::JNIEnv<'j>) -> Result<JObject<'j>, jni::errors::Error> {
191		let class = env.find_class(Self::CLASS)?;
192		let (msb, lsb) = self.as_u64_pair();
193		let msb = i64::from_ne_bytes(msb.to_ne_bytes());
194		let lsb = i64::from_ne_bytes(lsb.to_ne_bytes());
195		env.new_object(&class, "(JJ)V", &[jni::objects::JValueGen::Long(msb), jni::objects::JValueGen::Long(lsb)])
196	}
197}