jni_toolbox/
from_java.rs

1use jni::objects::{JObject, JObjectArray, JPrimitiveArray, JString, TypeArray};
2
3
4/// Used in the generated code to have proper type bindings. You probably didn't want
5/// to call this directly.
6pub fn from_java_static<'j, T: FromJava<'j>>(env: &mut jni::JNIEnv<'j>, val: T::From) -> Result<T, jni::errors::Error> {
7	T::from_java(env, val)
8}
9
10/// Specifies how a Java type should be converted before being fed to Rust.
11pub trait FromJava<'j> : Sized {
12	/// The JNI type representing the input.
13	type From : Sized;
14	/// Attempts to convert this Java object into its Rust counterpart.
15	fn from_java(env: &mut jni::JNIEnv<'j>, value: Self::From) -> Result<Self, jni::errors::Error>;
16}
17
18macro_rules! auto_from_java {
19	($t: ty, $j: ty) => {
20		impl<'j> FromJava<'j> for $t {
21			type From = $j;
22		
23			#[inline]
24			fn from_java(_: &mut jni::JNIEnv, value: Self::From) -> Result<Self, jni::errors::Error> {
25				Ok(value)
26			}
27		}
28	};
29}
30
31auto_from_java!(i8, jni::sys::jbyte);
32auto_from_java!(i16, jni::sys::jshort);
33auto_from_java!(i32, jni::sys::jint);
34auto_from_java!(i64, jni::sys::jlong);
35auto_from_java!(f32, jni::sys::jfloat);
36auto_from_java!(f64, jni::sys::jdouble);
37auto_from_java!(JObject<'j>, JObject<'j>);
38auto_from_java!(JString<'j>, JString<'j>);
39auto_from_java!(JObjectArray<'j>, JObjectArray<'j>);
40
41impl<'j, T: TypeArray> FromJava<'j> for JPrimitiveArray<'j, T> {
42	type From = JPrimitiveArray<'j, T>;
43
44	#[inline]
45	fn from_java(_: &mut jni::JNIEnv, value: Self::From) -> Result<Self, jni::errors::Error> {
46		Ok(value)
47	}
48}
49
50impl<'j> FromJava<'j> for char {
51	type From = jni::sys::jchar;
52
53	#[inline]
54	fn from_java(_: &mut jni::JNIEnv, value: Self::From) -> Result<Self, jni::errors::Error> {
55		char::from_u32(value.into()).ok_or_else(|| jni::errors::Error::WrongJValueType("char", "invalid u16"))
56	}
57}
58
59impl<'j> FromJava<'j> for bool {
60	type From = jni::sys::jboolean;
61
62	#[inline]
63	fn from_java(_: &mut jni::JNIEnv, value: Self::From) -> Result<Self, jni::errors::Error> {
64		Ok(value != 0)
65	}
66}
67
68impl<'j> FromJava<'j> for String {
69	type From = JString<'j>;
70
71	fn from_java(env: &mut jni::JNIEnv<'j>, value: Self::From) -> Result<Self, jni::errors::Error> {
72		if value.is_null() { return Err(jni::errors::Error::NullPtr("string can't be null")) };
73		Ok(env.get_string(&value)?.into())
74	}
75}
76
77impl<'j, T> FromJava<'j> for Option<T>
78where
79	T: FromJava<'j, From: AsRef<JObject<'j>>>,
80{
81	type From = T::From;
82
83	fn from_java(env: &mut jni::JNIEnv<'j>, value: Self::From) -> Result<Self, jni::errors::Error> {
84		if value.as_ref().is_null() { return Ok(None) };
85		Ok(Some(T::from_java(env, value)?))
86	}
87}
88
89impl<'j, T: FromJava<'j, From = JObject<'j>>> FromJava<'j> for Vec<T> {
90	type From = JObjectArray<'j>;
91
92	fn from_java(env: &mut jni::JNIEnv<'j>, value: Self::From) -> Result<Self, jni::errors::Error> {
93		let len = env.get_array_length(&value)?;
94		let mut out = Vec::new();
95		for i in 0..len {
96			let el = env.get_object_array_element(&value, i)?;
97			out.push(T::from_java(env, el)?);
98		}
99		Ok(out)
100	}
101}
102
103macro_rules! auto_from_java_primitive_array {
104	($primitive:ty, $fn:ident) => {
105		impl<'j> FromJava<'j> for Vec<$primitive> {
106			type From = JPrimitiveArray<'j, $primitive>;
107		
108			fn from_java(env: &mut jni::JNIEnv<'j>, value: Self::From) -> Result<Self, jni::errors::Error> {
109				let len = env.get_array_length(&value)?.max(0) as usize; // should be always safe but TODO
110				let mut out = vec![<$primitive>::default(); len];
111				env.$fn(value, 0, &mut out)?;
112				Ok(out)
113			}
114		}
115	};
116}
117
118auto_from_java_primitive_array!(i8, get_byte_array_region);
119auto_from_java_primitive_array!(i16, get_short_array_region);
120auto_from_java_primitive_array!(i32, get_int_array_region);
121auto_from_java_primitive_array!(i64, get_long_array_region);
122auto_from_java_primitive_array!(f32, get_float_array_region);
123auto_from_java_primitive_array!(f64, get_double_array_region);
124
125impl<'j> FromJava<'j> for Vec<bool> {
126	type From = JPrimitiveArray<'j, u8>;
127
128	fn from_java(env: &mut jni::JNIEnv<'j>, value: Self::From) -> Result<Self, jni::errors::Error> {
129		let len = env.get_array_length(&value)?.max(0) as usize; // should be always safe but TODO
130		let mut out = vec![<u8>::default(); len];
131		env.get_boolean_array_region(value, 0, &mut out)?;
132		Ok(out.into_iter().map(|x| x != 0).collect())
133	}
134}
135
136impl<'j> FromJava<'j> for Vec<char> {
137	type From = JPrimitiveArray<'j, u16>;
138
139	fn from_java(env: &mut jni::JNIEnv<'j>, value: Self::From) -> Result<Self, jni::errors::Error> {
140		let len = env.get_array_length(&value)?.max(0) as usize; // should be always safe but TODO
141		let mut out = vec![<u16>::default(); len];
142		env.get_char_array_region(value, 0, &mut out)?;
143		Ok(
144			out
145				.into_iter()
146				.map(|x| char::from_u32(x.into()).unwrap_or_default())
147				.collect()
148		)
149	}
150}
151
152#[cfg(feature = "uuid")]
153impl<'j> FromJava<'j> for uuid::Uuid {
154	type From = JObject<'j>;
155	fn from_java(env: &mut jni::JNIEnv<'j>, uuid: Self::From) -> Result<Self, jni::errors::Error> {
156		let lsb = u64::from_ne_bytes(
157			env.call_method(&uuid, "getLeastSignificantBits", "()J", &[])?
158				.j()?
159				.to_ne_bytes()
160		);
161
162		let msb = u64::from_ne_bytes(
163			env.call_method(&uuid, "getMostSignificantBits", "()J", &[])?
164				.j()?
165				.to_ne_bytes()
166		);
167		
168		Ok(uuid::Uuid::from_u64_pair(msb, lsb))
169	}
170}