1use java_string::*;
2use jni::string::String;
3use jni::*;
4use jni_sys;
5use std::fmt;
6use std::os::raw::c_char;
7use std::ptr;
8
9include!("call_jni_method.rs");
10include!("generate_class.rs");
11
12#[derive(Debug)]
17pub struct Class<'env> {
18 object: Object<'env>,
19}
20
21impl<'env> Class<'env> {
22 pub fn find<'a>(
27 env: &'a JniEnv<'a>,
28 class_name: &str,
29 token: &NoException<'a>,
30 ) -> JavaResult<'a, Class<'a>> {
31 let class_name = to_java_string(class_name);
32 let raw_class = unsafe {
35 call_nullable_jni_method!(env, FindClass, token, class_name.as_ptr() as *const c_char)?
36 };
37 Ok(unsafe { Self::from_raw(env, raw_class) })
39 }
40
41 pub fn define<'a>(
45 env: &'a JniEnv<'a>,
46 bytes: &[u8],
47 token: &NoException<'a>,
48 ) -> JavaResult<'a, Class<'a>> {
49 let raw_class = unsafe {
52 call_nullable_jni_method!(
53 env,
54 DefineClass,
55 token,
56 ptr::null() as *const c_char,
57 ptr::null_mut() as jni_sys::jobject,
58 bytes.as_ptr() as *const jni_sys::jbyte,
59 bytes.len() as jni_sys::jsize
60 )?
61 };
62 Ok(unsafe { Self::from_raw(env, raw_class) })
64 }
65
66 pub fn parent(&self, _token: &NoException) -> Option<Class<'env>> {
72 let raw_java_class =
74 unsafe { call_jni_method!(self.env(), GetSuperclass, self.raw_object()) };
75 if raw_java_class == ptr::null_mut() {
76 None
77 } else {
78 Some(unsafe { Self::__from_jni(self.env(), raw_java_class) })
80 }
81 }
82
83 pub fn is_subtype_of(&self, class: &Class, _token: &NoException) -> bool {
91 let assignable = unsafe {
93 call_jni_method!(
94 self.env(),
95 IsAssignableFrom,
96 self.raw_object() as jni_sys::jclass,
97 class.raw_object() as jni_sys::jclass
98 )
99 };
100 unsafe { bool::__from_jni(self.env(), assignable) }
102 }
103
104 unsafe fn from_raw<'a>(env: &'a JniEnv<'a>, raw_class: jni_sys::jclass) -> Class<'a> {
106 Class {
107 object: Object::__from_jni(env, raw_class as jni_sys::jobject),
108 }
109 }
110}
111
112java_class!(
113 Class,
114 "[`Class`](struct.Class.html)",
115 constructors = (),
116 methods = (),
117 static_methods = (),
118);
119
120#[cfg(test)]
121pub fn test_class<'env>(env: &'env JniEnv<'env>, raw_object: jni_sys::jobject) -> Class<'env> {
122 Class {
123 object: test_object(env, raw_object),
124 }
125}
126
127#[cfg(test)]
128mod class_tests {
129 use super::*;
130 use jni::testing::*;
131 use std::mem;
132 use std::ops::Deref;
133
134 fn test_value<'env>(env: &'env JniEnv<'env>, raw_object: jni_sys::jobject) -> Class<'env> {
135 test_class(env, raw_object)
136 }
137
138 generate_tests!(Class, "Ljava/lang/Class;");
139
140 #[test]
141 fn find() {
142 const RAW_OBJECT: jni_sys::jobject = 0x91011 as jni_sys::jobject;
143 let calls = test_raw_jni_env!(vec![JniCall::FindClass(FindClass {
144 name: "test-class".to_owned(),
145 result: RAW_OBJECT,
146 })]);
147 let vm = test_vm(ptr::null_mut());
148 let env = test_env(&vm, calls.env);
149 let class = Class::find(&env, "test-class", &NoException::test()).unwrap();
150 calls.assert_eq(&class, RAW_OBJECT);
151 }
152
153 #[test]
154 fn find_not_found() {
155 const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
156 let calls = test_raw_jni_env!(vec![
157 JniCall::FindClass(FindClass {
158 name: "test-class".to_owned(),
159 result: ptr::null_mut(),
160 }),
161 JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
162 JniCall::ExceptionClear(ExceptionClear {}),
163 ]);
164 let vm = test_vm(ptr::null_mut());
165 let env = test_env(&vm, calls.env);
166 let exception = Class::find(&env, "test-class", &NoException::test()).unwrap_err();
167 calls.assert_eq(&exception, EXCEPTION);
168 }
169
170 #[test]
171 fn define() {
172 const RAW_OBJECT: jni_sys::jobject = 0x91011 as jni_sys::jobject;
173 let calls = test_raw_jni_env!(vec![JniCall::DefineClass(DefineClass {
174 name: ptr::null(),
175 loader: ptr::null_mut(),
176 buffer: vec![17, (230 as u8) as i8],
177 result: RAW_OBJECT,
178 })]);
179 let vm = test_vm(ptr::null_mut());
180 let env = test_env(&vm, calls.env);
181 let class = Class::define(&env, &[17, 230], &NoException::test()).unwrap();
182 calls.assert_eq(&class, RAW_OBJECT);
183 }
184
185 #[test]
186 fn define_not_found() {
187 const EXCEPTION: jni_sys::jobject = 0x2835 as jni_sys::jobject;
188 let calls = test_raw_jni_env!(vec![
189 JniCall::DefineClass(DefineClass {
190 name: ptr::null(),
191 loader: ptr::null_mut(),
192 buffer: vec![17, (230 as u8) as i8],
193 result: ptr::null_mut(),
194 }),
195 JniCall::ExceptionOccurred(ExceptionOccurred { result: EXCEPTION }),
196 JniCall::ExceptionClear(ExceptionClear {}),
197 ]);
198 let vm = test_vm(ptr::null_mut());
199 let env = test_env(&vm, calls.env);
200 let exception = Class::define(&env, &[17, 230], &NoException::test()).unwrap_err();
201 calls.assert_eq(&exception, EXCEPTION);
202 }
203
204 #[test]
205 fn is_subtype_of() {
206 const RAW_CLASS1: jni_sys::jobject = 0x2835 as jni_sys::jobject;
207 const RAW_CLASS2: jni_sys::jobject = 0x294875 as jni_sys::jobject;
208 let calls = test_raw_jni_env!(vec![JniCall::IsAssignableFrom(IsAssignableFrom {
209 class1: RAW_CLASS1,
210 class2: RAW_CLASS2,
211 result: jni_sys::JNI_TRUE,
212 })]);
213 let vm = test_vm(ptr::null_mut());
214 let env = test_env(&vm, calls.env);
215 let class1 = test_class(&env, RAW_CLASS1);
216 let class2 = test_class(&env, RAW_CLASS2);
217 assert!(class1.is_subtype_of(&class2, &NoException::test()));
218 }
219
220 #[test]
221 fn is_not_subtype_of() {
222 const RAW_CLASS1: jni_sys::jobject = 0x2835 as jni_sys::jobject;
223 const RAW_CLASS2: jni_sys::jobject = 0x294875 as jni_sys::jobject;
224 let calls = test_raw_jni_env!(vec![JniCall::IsAssignableFrom(IsAssignableFrom {
225 class1: RAW_CLASS1,
226 class2: RAW_CLASS2,
227 result: jni_sys::JNI_FALSE,
228 })]);
229 let vm = test_vm(ptr::null_mut());
230 let env = test_env(&vm, calls.env);
231 let class1 = test_class(&env, RAW_CLASS1);
232 let class2 = test_class(&env, RAW_CLASS2);
233 assert!(!class1.is_subtype_of(&class2, &NoException::test()));
234 }
235
236 #[test]
237 fn parent() {
238 const RAW_CLASS1: jni_sys::jobject = 0x2835 as jni_sys::jobject;
239 const RAW_CLASS2: jni_sys::jobject = 0x294875 as jni_sys::jobject;
240 let calls = test_raw_jni_env!(vec![JniCall::GetSuperclass(GetSuperclass {
241 class: RAW_CLASS1,
242 result: RAW_CLASS2,
243 })]);
244 let vm = test_vm(ptr::null_mut());
245 let env = test_env(&vm, calls.env);
246 let class = test_class(&env, RAW_CLASS1);
247 let parent = class.parent(&NoException::test()).unwrap();
248 calls.assert_eq(&parent, RAW_CLASS2);
249 }
250
251 #[test]
252 fn no_parent() {
253 const RAW_CLASS: jni_sys::jobject = 0x2835 as jni_sys::jobject;
254 let calls = test_raw_jni_env!(vec![JniCall::GetSuperclass(GetSuperclass {
255 class: RAW_CLASS,
256 result: ptr::null_mut(),
257 })]);
258 let vm = test_vm(ptr::null_mut());
259 let env = test_env(&vm, calls.env);
260 let class = test_class(&env, RAW_CLASS);
261 assert!(class.parent(&NoException::test()).is_none());
262 }
263}