1use crate::logger::debug;
16use crate::{cache, errors, jni_utils, InvocationArg, Jvm};
17use jni_sys::jobject;
18use serde::de::DeserializeOwned;
19use serde::Serialize;
20use std::any::Any;
21use std::convert::TryFrom;
22use std::sync::mpsc::{Receiver, Sender};
23
24#[derive(Serialize)]
27pub struct Instance {
28 pub(crate) class_name: String,
30 #[serde(skip)]
34 pub(crate) jinstance: jobject,
35 #[serde(skip)]
36 pub(crate) skip_deleting_jobject: bool,
37}
38
39impl Instance {
40 pub(crate) fn new(obj: jobject, classname: &str) -> errors::Result<Instance> {
43 Ok(Instance {
44 jinstance: obj,
45 class_name: classname.to_string(),
46 skip_deleting_jobject: false,
47 })
48 }
49
50 pub fn class_name(&self) -> &str {
52 self.class_name.as_ref()
53 }
54
55 pub fn java_object(mut self) -> jobject {
57 self.skip_deleting_jobject = true;
58 self.jinstance
59 }
60
61 #[deprecated(
62 since = "0.12.0",
63 note = "Please use Instance::from_jobject or Instance::from_jobject_with_global_ref instead"
64 )]
65 pub fn from(obj: jobject) -> errors::Result<Instance> {
66 let _jvm = cache::get_thread_local_env().map_err(|_| Jvm::attach_thread());
67
68 let global =
69 jni_utils::create_global_ref_from_local_ref(obj, cache::get_thread_local_env()?)?;
70 Ok(Instance {
71 jinstance: global,
72 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
73 skip_deleting_jobject: false,
74 })
75 }
76
77 pub fn from_jobject(obj: jobject) -> errors::Result<Instance> {
78 let _jvm = cache::get_thread_local_env().map_err(|_| Jvm::attach_thread());
79
80 Ok(Instance {
81 jinstance: obj,
82 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
83 skip_deleting_jobject: false,
84 })
85 }
86
87 pub fn from_jobject_with_global_ref(obj: jobject) -> errors::Result<Instance> {
88 let _jvm = cache::get_thread_local_env().map_err(|_| Jvm::attach_thread());
89
90 let global =
91 jni_utils::create_global_ref_from_local_ref(obj, cache::get_thread_local_env()?)?;
92 Ok(Instance {
93 jinstance: global,
94 class_name: cache::UNKNOWN_FOR_RUST.to_string(),
95 skip_deleting_jobject: false,
96 })
97 }
98
99 fn _weak_ref(&self) -> errors::Result<Instance> {
101 Ok(Instance {
102 class_name: self.class_name.clone(),
103 jinstance: jni_utils::_create_weak_global_ref_from_global_ref(
104 self.jinstance,
105 cache::get_thread_local_env()?,
106 )?,
107 skip_deleting_jobject: false,
108 })
109 }
110}
111
112impl TryFrom<InvocationArg> for Instance {
113 type Error = errors::J4RsError;
114 fn try_from(invocation_arg: InvocationArg) -> errors::Result<Instance> {
115 let obj = invocation_arg.as_java_ptr_with_local_ref(cache::get_thread_local_env()?)?;
116 Instance::new(obj, invocation_arg.class_name())
117 }
118}
119
120impl TryFrom<jobject> for Instance {
121 type Error = errors::J4RsError;
122 fn try_from(obj: jobject) -> errors::Result<Instance> {
123 Instance::from_jobject_with_global_ref(obj)
124 }
125}
126
127impl Drop for Instance {
128 fn drop(&mut self) {
129 debug(&format!("Dropping an instance of {}", self.class_name));
130 if !self.skip_deleting_jobject {
131 if let Some(j_env) = cache::get_thread_local_env_opt() {
132 jni_utils::delete_java_ref(j_env, self.jinstance);
133 }
134 }
135 }
136}
137
138unsafe impl Send for Instance {}
140
141pub struct InstanceReceiver {
149 pub(crate) rx: Box<Receiver<Instance>>,
150 tx_address: u64,
151}
152
153impl InstanceReceiver {
154 pub(crate) fn new(rx: Receiver<Instance>, tx_address: u64) -> InstanceReceiver {
155 InstanceReceiver {
156 rx: Box::new(rx),
157 tx_address,
158 }
159 }
160
161 pub fn rx(&self) -> &Receiver<Instance> {
162 &self.rx
163 }
164}
165
166impl Drop for InstanceReceiver {
167 fn drop(&mut self) {
168 if self.tx_address > 0 {
169 debug("Dropping an InstanceReceiver");
170 let p = self.tx_address as *mut Sender<Instance>;
171 unsafe {
172 let tx = Box::from_raw(p);
173 drop(tx);
174 }
175 }
176 }
177}
178
179pub struct ChainableInstance<'a> {
181 instance: Instance,
182 jvm: &'a Jvm,
183}
184
185impl<'a> ChainableInstance<'a> {
186 pub(crate) fn new(instance: Instance, jvm: &'a Jvm) -> ChainableInstance<'a> {
187 ChainableInstance { instance, jvm }
188 }
189
190 pub(crate) fn new_with_instance_ref(
191 instance: &Instance,
192 jvm: &'a Jvm,
193 ) -> errors::Result<ChainableInstance<'a>> {
194 let cloned = jvm.clone_instance(instance)?;
195 Ok(ChainableInstance {
196 instance: cloned,
197 jvm,
198 })
199 }
200
201 pub fn collect(self) -> Instance {
202 self.instance
203 }
204
205 pub fn invoke(
207 &self,
208 method_name: &str,
209 inv_args: &[InvocationArg],
210 ) -> errors::Result<ChainableInstance> {
211 let instance = self.jvm.invoke(&self.instance, method_name, inv_args)?;
212 Ok(ChainableInstance::new(instance, self.jvm))
213 }
214
215 pub fn clone_instance(&self) -> errors::Result<ChainableInstance> {
217 let instance = self.jvm.clone_instance(&self.instance)?;
218 Ok(ChainableInstance::new(instance, self.jvm))
219 }
220
221 pub fn cast(&self, to_class: &str) -> errors::Result<ChainableInstance> {
223 let instance = self.jvm.cast(&self.instance, to_class)?;
224 Ok(ChainableInstance::new(instance, self.jvm))
225 }
226
227 pub fn field(&self, field_name: &str) -> errors::Result<ChainableInstance> {
229 let instance = self.jvm.field(&self.instance, field_name)?;
230 Ok(ChainableInstance::new(instance, self.jvm))
231 }
232
233 pub fn to_rust<T: Any>(self) -> errors::Result<T>
235 where
236 T: DeserializeOwned,
237 {
238 self.jvm.to_rust(self.instance)
239 }
240
241 pub fn to_rust_boxed<T: Any>(self) -> errors::Result<Box<T>>
243 where
244 T: DeserializeOwned,
245 {
246 self.jvm.to_rust_boxed(self.instance)
247 }
248}
249
250#[cfg(test)]
251mod instance_unit_tests {
252 use crate::*;
253 use crate::lib_unit_tests::create_tests_jvm;
254
255 #[test]
256 fn is_null() -> errors::Result<()> {
257 let jvm = create_tests_jvm()?;
258 let test_instance = jvm
259 .create_instance("org.astonbitecode.j4rs.tests.MyTest", InvocationArg::empty())
260 ?;
261 let maybe_null = jvm.invoke(&test_instance, "getNullInteger", InvocationArg::empty())?;
262 let is_null =
263 jvm.invoke_static(
264 "java.util.Objects",
265 "isNull",
266 &[InvocationArg::try_from(maybe_null)?])?;
267 let is_null: bool = jvm.to_rust(is_null)?;
268 assert!(is_null);
269 Ok(())
270 }
271
272 #[test]
273 fn try_from_jobject() -> errors::Result<()> {
274 let c = std::ptr::null_mut();
275 let instance = Instance::try_from(c)?;
276 assert!(instance.java_object() == std::ptr::null_mut());
277 Ok(())
278 }
279}