java_oxide/
env.rs

1use crate::{AsArg, Local, Ref, ReferenceType, StringChars, ThrowableType, VM};
2use jni_sys::*;
3use std::{
4    ffi::CStr,
5    marker::PhantomData,
6    ptr::{self, null_mut},
7    sync::{
8        OnceLock,
9        atomic::{AtomicPtr, Ordering},
10    },
11};
12
13/// FFI:  Use **Env** instead of `*const JNIEnv`.  This represents a per-thread Java exection environment.
14///
15/// A "safe" alternative to `jni_sys::JNIEnv` raw pointers, with the following caveats:
16///
17/// 1)  A null env will result in **undefined behavior**.  Java should not be invoking your native functions with a null
18///     *mut JNIEnv, however, so I don't believe this is a problem in practice unless you've bindgened the C header
19///     definitions elsewhere, calling them (requiring `unsafe`), and passing null pointers (generally UB for JNI
20///     functions anyways, so can be seen as a caller soundness issue.)
21///
22/// 2)  Allowing the underlying JNIEnv to be modified is **undefined behavior**.  I don't believe the JNI libraries
23///     modify the JNIEnv, so as long as you're not accepting a *mut JNIEnv elsewhere, using unsafe to dereference it,
24///     and mucking with the methods on it yourself, I believe this "should" be fine.
25///
26/// Most methods of `Env` are supposed to be used by generated bindings.
27///
28/// # Example
29///
30/// ### MainActivity.java
31///
32/// ```java
33/// package com.maulingmonkey.example;
34///
35/// public class MainActivity extends androidx.appcompat.app.AppCompatActivity {
36///     @Override
37///     public native boolean dispatchKeyEvent(android.view.KeyEvent keyEvent);
38///
39///     // ...
40/// }
41/// ```
42///
43/// ### main_activity.rs
44///
45/// ```ignore
46/// use java_oxide::{Env, Arg};
47/// use java_oxide::sys::{jboolean, JNI_TRUE};
48/// use bindings::java::lang::Object;
49/// use bindings::android::view::KeyEvent;
50///
51/// mod bindings; // Generated by `java-oxide-gen`
52///
53/// #[unsafe(no_mangle)] pub extern "system"
54/// fn Java_com_maulingmonkey_example_MainActivity_dispatchKeyEvent<'env>(
55///     env:       Env<'env>,
56///     _this:     Arg<Object>,
57///     key_event: Arg<KeyEvent>,
58/// ) -> jboolean {
59///     let key_event = unsafe { key_event.into_ref(env) };
60///     // ...
61///     JNI_TRUE
62/// }
63/// ```
64#[repr(transparent)]
65#[derive(Copy, Clone)]
66pub struct Env<'env> {
67    env: *mut JNIEnv,
68    pd: PhantomData<&'env mut JNIEnv>,
69}
70
71static CLASS_LOADER: AtomicPtr<_jobject> = AtomicPtr::new(null_mut());
72
73#[allow(clippy::missing_safety_doc)]
74#[allow(unsafe_op_in_unsafe_fn)]
75impl<'env> Env<'env> {
76    pub unsafe fn from_raw(ptr: *mut JNIEnv) -> Self {
77        Self {
78            env: ptr,
79            pd: PhantomData,
80        }
81    }
82
83    pub fn as_raw(&self) -> *mut JNIEnv {
84        self.env
85    }
86
87    pub fn vm(&self) -> VM {
88        let jni_env = self.as_raw();
89        let mut vm = null_mut();
90        let err = unsafe { ((**jni_env).v1_2.GetJavaVM)(jni_env, &mut vm) };
91        assert_eq!(err, JNI_OK);
92        assert_ne!(vm, null_mut());
93        unsafe { VM::from_raw(vm) }
94    }
95
96    // String methods
97
98    pub unsafe fn new_string(self, chars: *const jchar, len: jsize) -> jstring {
99        let result = ((**self.env).v1_2.NewString)(self.env, chars as *const _, len);
100        assert!(!result.is_null());
101        result
102    }
103
104    pub unsafe fn get_string_length(self, string: jstring) -> jsize {
105        ((**self.env).v1_2.GetStringLength)(self.env, string)
106    }
107
108    pub unsafe fn get_string_chars(self, string: jstring) -> *const jchar {
109        ((**self.env).v1_2.GetStringChars)(self.env, string, null_mut()) as *const _
110    }
111
112    pub unsafe fn release_string_chars(self, string: jstring, chars: *const jchar) {
113        ((**self.env).v1_2.ReleaseStringChars)(self.env, string, chars as *const _)
114    }
115
116    // Query Methods
117
118    /// Set a custom class loader to use instead of JNI `FindClass` calls.
119    ///
120    /// When calling Java methods, `java-oxide` may need to resolve class names (as strings)
121    /// into `jclass` pointers. The JNI API provides `FindClass` to do it. However, it is
122    /// hardcoded to use the class loader for the class that called the currently-running native method.
123    ///
124    /// This works fine most of the time, except:
125    ///
126    /// - On a thread created by native code (such as with `std::thread::spawn()`), there is no
127    ///   "class that called a native method" in the call stack, since the execution already started
128    ///   in native code. In this case, `FindClass` falls back to the system class loader.
129    /// - On Android, the system class loader can't find classes for your application, it can only find
130    ///   classes from the Android frameworks.
131    ///
132    /// `set_class_loader` allows you to set a `ClassLoader` instance that `java-oxide` will use to
133    /// resolve class names, by calling the `loadClass` method, instead of doing JNI `FindClass` calls.
134    ///
135    /// Calling this with a null `classloader` reverts back to using JNI `FindClass`.
136    ///
137    /// # Safety
138    ///
139    /// - `classloader` must be a global reference to a `java.lang.ClassLoader` instance.
140    /// - The library does not take ownership of the global reference. I.e. it will not delete it if you
141    ///   call `set_class_loader` with another class loader, or with null.
142    pub unsafe fn set_class_loader(classloader: jobject) {
143        CLASS_LOADER.store(classloader, Ordering::Relaxed);
144    }
145
146    /// Checks if an exception has occurred; if occurred, it clears the exception to make the next
147    /// JNI call possible, then it returns the exception as an `Err`.
148    ///
149    /// XXX: Make this method public after making sure that it has a proper name.
150    /// Note that there is `ExceptionCheck` in JNI functions, which does not create a
151    /// local reference to the exception object.
152    pub(crate) fn exception_check<E: ThrowableType>(self) -> Result<(), Local<'env, E>> {
153        unsafe {
154            let exception = ((**self.env).v1_2.ExceptionOccurred)(self.env);
155            if exception.is_null() {
156                Ok(())
157            } else {
158                ((**self.env).v1_2.ExceptionClear)(self.env);
159                Err(Local::from_raw(self, exception))
160            }
161        }
162    }
163
164    unsafe fn exception_to_string(self, exception: jobject) -> String {
165        static METHOD_GET_MESSAGE: OnceLock<usize> = OnceLock::new();
166        let throwable_get_message = *METHOD_GET_MESSAGE.get_or_init(|| {
167            // use JNI FindClass to avoid infinte recursion.
168            let throwable_class = self.require_class_jni(c"java/lang/Throwable");
169            let method =
170                self.require_method(throwable_class, c"getMessage", c"()Ljava/lang/String;");
171            ((**self.env).v1_2.DeleteLocalRef)(self.env, throwable_class);
172            method.addr()
173        }) as jmethodID; // it is a global ID
174
175        let message = ((**self.env).v1_2.CallObjectMethodA)(
176            self.env,
177            exception,
178            throwable_get_message,
179            ptr::null_mut(),
180        );
181        let e2: *mut _jobject = ((**self.env).v1_2.ExceptionOccurred)(self.env);
182        if !e2.is_null() {
183            ((**self.env).v1_2.ExceptionClear)(self.env);
184            panic!("exception happened calling Throwable.getMessage()");
185        }
186
187        StringChars::from_env_jstring(self, message).to_string_lossy()
188    }
189
190    /// Note: the returned `jclass` is actually a new local reference of the class object.
191    pub unsafe fn require_class(self, class: &CStr) -> jclass {
192        // First try with JNI FindClass.
193        let c = ((**self.env).v1_2.FindClass)(self.env, class.as_ptr());
194        let exception: *mut _jobject = ((**self.env).v1_2.ExceptionOccurred)(self.env);
195        if !exception.is_null() {
196            ((**self.env).v1_2.ExceptionClear)(self.env);
197        }
198        if !c.is_null() {
199            return c;
200        }
201
202        // If class is not found and we have a classloader set, try that.
203        let classloader = CLASS_LOADER.load(Ordering::Relaxed);
204        if !classloader.is_null() {
205            let chars = class
206                .to_str()
207                .unwrap()
208                .replace('/', ".")
209                .encode_utf16()
210                .collect::<Vec<_>>();
211            let string = unsafe { self.new_string(chars.as_ptr(), chars.len() as jsize) };
212
213            static CL_METHOD: OnceLock<usize> = OnceLock::new();
214            let cl_method = *CL_METHOD.get_or_init(|| {
215                // We still use JNI FindClass for this, to avoid a chicken-and-egg situation.
216                // If the system class loader cannot find java.lang.ClassLoader, things are pretty broken!
217                let cl_class = self.require_class_jni(c"java/lang/ClassLoader");
218                let cl_method = self.require_method(
219                    cl_class,
220                    c"loadClass",
221                    c"(Ljava/lang/String;)Ljava/lang/Class;",
222                );
223                ((**self.env).v1_2.DeleteLocalRef)(self.env, cl_class);
224                cl_method.addr()
225            }) as jmethodID; // it is a global ID
226
227            let args = [jvalue { l: string }];
228            let result: *mut _jobject = ((**self.env).v1_2.CallObjectMethodA)(
229                self.env,
230                classloader,
231                cl_method,
232                args.as_ptr(),
233            );
234            let exception: *mut _jobject = ((**self.env).v1_2.ExceptionOccurred)(self.env);
235            if !exception.is_null() {
236                ((**self.env).v1_2.ExceptionClear)(self.env);
237                panic!(
238                    "exception happened calling loadClass(): {}",
239                    self.exception_to_string(exception)
240                );
241            } else if result.is_null() {
242                panic!("loadClass() returned null");
243            }
244
245            ((**self.env).v1_2.DeleteLocalRef)(self.env, string);
246
247            return result as jclass;
248        }
249
250        // If neither found the class, panic.
251        panic!("couldn't load class {class:?}");
252    }
253
254    unsafe fn require_class_jni(self, class: &CStr) -> jclass {
255        let res = ((**self.env).v1_2.FindClass)(self.env, class.as_ptr());
256        if res.is_null() {
257            ((**self.env).v1_2.ExceptionClear)(self.env);
258            panic!("could not find class {class:?}");
259        }
260        res
261    }
262
263    // used only for debugging
264    unsafe fn get_class_name(self, class: jclass) -> String {
265        let classclass = self.require_class_jni(c"java/lang/Class");
266
267        // don't use self.require_method() here to avoid recursion!
268        let method = ((**self.env).v1_2.GetMethodID)(
269            self.env,
270            classclass,
271            c"getName".as_ptr(),
272            c"()Ljava/lang/String;".as_ptr(),
273        );
274        if method.is_null() {
275            ((**self.env).v1_2.ExceptionClear)(self.env);
276            ((**self.env).v1_2.DeleteLocalRef)(self.env, classclass);
277            return "??? (couldn't get class getName method)".to_string();
278        }
279
280        // Ignore error here
281        let string = ((**self.env).v1_2.CallObjectMethod)(self.env, class, method);
282        if string.is_null() {
283            return "??? (getName returned null string)".to_string();
284        }
285        let chars = ((**self.env).v1_2.GetStringUTFChars)(self.env, string, ptr::null_mut());
286        if chars.is_null() {
287            ((**self.env).v1_2.DeleteLocalRef)(self.env, string);
288            ((**self.env).v1_2.DeleteLocalRef)(self.env, classclass);
289            return "??? (GetStringUTFChars returned null chars)".to_string();
290        }
291
292        let cchars = CStr::from_ptr(chars);
293        let res = cchars.to_string_lossy().to_string();
294
295        ((**self.env).v1_2.ReleaseStringUTFChars)(self.env, string, chars);
296        ((**self.env).v1_2.DeleteLocalRef)(self.env, string);
297        ((**self.env).v1_2.DeleteLocalRef)(self.env, classclass);
298
299        res
300    }
301
302    pub unsafe fn require_method(
303        self,
304        class: jclass,
305        method: &CStr,
306        descriptor: &CStr,
307    ) -> jmethodID {
308        let res =
309            ((**self.env).v1_2.GetMethodID)(self.env, class, method.as_ptr(), descriptor.as_ptr());
310        if res.is_null() {
311            ((**self.env).v1_2.ExceptionClear)(self.env);
312            let class_name = self.get_class_name(class);
313            panic!("could not find method {method:?} {descriptor:?} on class {class_name:?}");
314        }
315        res
316    }
317
318    pub unsafe fn require_static_method(
319        self,
320        class: jclass,
321        method: &CStr,
322        descriptor: &CStr,
323    ) -> jmethodID {
324        let res = ((**self.env).v1_2.GetStaticMethodID)(
325            self.env,
326            class,
327            method.as_ptr(),
328            descriptor.as_ptr(),
329        );
330        if res.is_null() {
331            ((**self.env).v1_2.ExceptionClear)(self.env);
332            let class_name = self.get_class_name(class);
333            panic!(
334                "could not find static method {method:?} {descriptor:?} on class {class_name:?}"
335            );
336        }
337        res
338    }
339
340    pub unsafe fn require_field(self, class: jclass, field: &CStr, descriptor: &CStr) -> jfieldID {
341        let res =
342            ((**self.env).v1_2.GetFieldID)(self.env, class, field.as_ptr(), descriptor.as_ptr());
343        if res.is_null() {
344            ((**self.env).v1_2.ExceptionClear)(self.env);
345            let class_name = self.get_class_name(class);
346            panic!("could not find field {field:?} {descriptor:?} on class {class_name:?}");
347        }
348        res
349    }
350
351    pub unsafe fn require_static_field(
352        self,
353        class: jclass,
354        field: &CStr,
355        descriptor: &CStr,
356    ) -> jfieldID {
357        let res = ((**self.env).v1_2.GetStaticFieldID)(
358            self.env,
359            class,
360            field.as_ptr(),
361            descriptor.as_ptr(),
362        );
363        if res.is_null() {
364            ((**self.env).v1_2.ExceptionClear)(self.env);
365            let class_name = self.get_class_name(class);
366            panic!("could not find static field {field:?} {descriptor:?} on class {class_name:?}");
367        }
368        res
369    }
370
371    // Multi-Query Methods
372    // XXX: Remove these unused functions.
373
374    pub unsafe fn require_class_method(
375        self,
376        class: &CStr,
377        method: &CStr,
378        descriptor: &CStr,
379    ) -> (jclass, jmethodID) {
380        let class = self.require_class(class);
381        (class, self.require_method(class, method, descriptor))
382    }
383
384    pub unsafe fn require_class_static_method(
385        self,
386        class: &CStr,
387        method: &CStr,
388        descriptor: &CStr,
389    ) -> (jclass, jmethodID) {
390        let class = self.require_class(class);
391        (class, self.require_static_method(class, method, descriptor))
392    }
393
394    pub unsafe fn require_class_field(
395        self,
396        class: &CStr,
397        method: &CStr,
398        descriptor: &CStr,
399    ) -> (jclass, jfieldID) {
400        let class = self.require_class(class);
401        (class, self.require_field(class, method, descriptor))
402    }
403
404    pub unsafe fn require_class_static_field(
405        self,
406        class: &CStr,
407        method: &CStr,
408        descriptor: &CStr,
409    ) -> (jclass, jfieldID) {
410        let class = self.require_class(class);
411        (class, self.require_static_field(class, method, descriptor))
412    }
413
414    // Constructor Methods
415
416    pub unsafe fn new_object_a<R: ReferenceType, E: ThrowableType>(
417        self,
418        class: jclass,
419        method: jmethodID,
420        args: *const jvalue,
421    ) -> Result<Local<'env, R>, Local<'env, E>> {
422        let result = ((**self.env).v1_2.NewObjectA)(self.env, class, method, args);
423        self.exception_check()?;
424        assert!(!result.is_null());
425        Ok(Local::from_raw(self, result))
426    }
427
428    // Instance Methods
429
430    pub unsafe fn call_object_method_a<R: ReferenceType, E: ThrowableType>(
431        self,
432        this: jobject,
433        method: jmethodID,
434        args: *const jvalue,
435    ) -> Result<Option<Local<'env, R>>, Local<'env, E>> {
436        let result = ((**self.env).v1_2.CallObjectMethodA)(self.env, this, method, args);
437        self.exception_check()?;
438        if result.is_null() {
439            Ok(None)
440        } else {
441            Ok(Some(Local::from_raw(self, result)))
442        }
443    }
444
445    pub unsafe fn call_boolean_method_a<E: ThrowableType>(
446        self,
447        this: jobject,
448        method: jmethodID,
449        args: *const jvalue,
450    ) -> Result<bool, Local<'env, E>> {
451        let result = ((**self.env).v1_2.CallBooleanMethodA)(self.env, this, method, args);
452        self.exception_check()?;
453        Ok(result != JNI_FALSE)
454    }
455
456    pub unsafe fn call_byte_method_a<E: ThrowableType>(
457        self,
458        this: jobject,
459        method: jmethodID,
460        args: *const jvalue,
461    ) -> Result<jbyte, Local<'env, E>> {
462        let result = ((**self.env).v1_2.CallByteMethodA)(self.env, this, method, args);
463        self.exception_check()?;
464        Ok(result)
465    }
466
467    pub unsafe fn call_char_method_a<E: ThrowableType>(
468        self,
469        this: jobject,
470        method: jmethodID,
471        args: *const jvalue,
472    ) -> Result<jchar, Local<'env, E>> {
473        let result = ((**self.env).v1_2.CallCharMethodA)(self.env, this, method, args);
474        self.exception_check()?;
475        Ok(result)
476    }
477
478    pub unsafe fn call_short_method_a<E: ThrowableType>(
479        self,
480        this: jobject,
481        method: jmethodID,
482        args: *const jvalue,
483    ) -> Result<jshort, Local<'env, E>> {
484        let result = ((**self.env).v1_2.CallShortMethodA)(self.env, this, method, args);
485        self.exception_check()?;
486        Ok(result)
487    }
488
489    pub unsafe fn call_int_method_a<E: ThrowableType>(
490        self,
491        this: jobject,
492        method: jmethodID,
493        args: *const jvalue,
494    ) -> Result<jint, Local<'env, E>> {
495        let result = ((**self.env).v1_2.CallIntMethodA)(self.env, this, method, args);
496        self.exception_check()?;
497        Ok(result)
498    }
499
500    pub unsafe fn call_long_method_a<E: ThrowableType>(
501        self,
502        this: jobject,
503        method: jmethodID,
504        args: *const jvalue,
505    ) -> Result<jlong, Local<'env, E>> {
506        let result = ((**self.env).v1_2.CallLongMethodA)(self.env, this, method, args);
507        self.exception_check()?;
508        Ok(result)
509    }
510
511    pub unsafe fn call_float_method_a<E: ThrowableType>(
512        self,
513        this: jobject,
514        method: jmethodID,
515        args: *const jvalue,
516    ) -> Result<jfloat, Local<'env, E>> {
517        let result = ((**self.env).v1_2.CallFloatMethodA)(self.env, this, method, args);
518        self.exception_check()?;
519        Ok(result)
520    }
521
522    pub unsafe fn call_double_method_a<E: ThrowableType>(
523        self,
524        this: jobject,
525        method: jmethodID,
526        args: *const jvalue,
527    ) -> Result<jdouble, Local<'env, E>> {
528        let result = ((**self.env).v1_2.CallDoubleMethodA)(self.env, this, method, args);
529        self.exception_check()?;
530        Ok(result)
531    }
532
533    pub unsafe fn call_void_method_a<E: ThrowableType>(
534        self,
535        this: jobject,
536        method: jmethodID,
537        args: *const jvalue,
538    ) -> Result<(), Local<'env, E>> {
539        ((**self.env).v1_2.CallVoidMethodA)(self.env, this, method, args);
540        self.exception_check()
541    }
542
543    // Static Methods
544
545    pub unsafe fn call_static_object_method_a<R: ReferenceType, E: ThrowableType>(
546        self,
547        class: jclass,
548        method: jmethodID,
549        args: *const jvalue,
550    ) -> Result<Option<Local<'env, R>>, Local<'env, E>> {
551        let result = ((**self.env).v1_2.CallStaticObjectMethodA)(self.env, class, method, args);
552        self.exception_check()?;
553        if result.is_null() {
554            Ok(None)
555        } else {
556            Ok(Some(Local::from_raw(self, result)))
557        }
558    }
559
560    pub unsafe fn call_static_boolean_method_a<E: ThrowableType>(
561        self,
562        class: jclass,
563        method: jmethodID,
564        args: *const jvalue,
565    ) -> Result<bool, Local<'env, E>> {
566        let result = ((**self.env).v1_2.CallStaticBooleanMethodA)(self.env, class, method, args);
567        self.exception_check()?;
568        Ok(result != JNI_FALSE)
569    }
570
571    pub unsafe fn call_static_byte_method_a<E: ThrowableType>(
572        self,
573        class: jclass,
574        method: jmethodID,
575        args: *const jvalue,
576    ) -> Result<jbyte, Local<'env, E>> {
577        let result = ((**self.env).v1_2.CallStaticByteMethodA)(self.env, class, method, args);
578        self.exception_check()?;
579        Ok(result)
580    }
581
582    pub unsafe fn call_static_char_method_a<E: ThrowableType>(
583        self,
584        class: jclass,
585        method: jmethodID,
586        args: *const jvalue,
587    ) -> Result<jchar, Local<'env, E>> {
588        let result = ((**self.env).v1_2.CallStaticCharMethodA)(self.env, class, method, args);
589        self.exception_check()?;
590        Ok(result)
591    }
592
593    pub unsafe fn call_static_short_method_a<E: ThrowableType>(
594        self,
595        class: jclass,
596        method: jmethodID,
597        args: *const jvalue,
598    ) -> Result<jshort, Local<'env, E>> {
599        let result = ((**self.env).v1_2.CallStaticShortMethodA)(self.env, class, method, args);
600        self.exception_check()?;
601        Ok(result)
602    }
603
604    pub unsafe fn call_static_int_method_a<E: ThrowableType>(
605        self,
606        class: jclass,
607        method: jmethodID,
608        args: *const jvalue,
609    ) -> Result<jint, Local<'env, E>> {
610        let result = ((**self.env).v1_2.CallStaticIntMethodA)(self.env, class, method, args);
611        self.exception_check()?;
612        Ok(result)
613    }
614
615    pub unsafe fn call_static_long_method_a<E: ThrowableType>(
616        self,
617        class: jclass,
618        method: jmethodID,
619        args: *const jvalue,
620    ) -> Result<jlong, Local<'env, E>> {
621        let result = ((**self.env).v1_2.CallStaticLongMethodA)(self.env, class, method, args);
622        self.exception_check()?;
623        Ok(result)
624    }
625
626    pub unsafe fn call_static_float_method_a<E: ThrowableType>(
627        self,
628        class: jclass,
629        method: jmethodID,
630        args: *const jvalue,
631    ) -> Result<jfloat, Local<'env, E>> {
632        let result = ((**self.env).v1_2.CallStaticFloatMethodA)(self.env, class, method, args);
633        self.exception_check()?;
634        Ok(result)
635    }
636
637    pub unsafe fn call_static_double_method_a<E: ThrowableType>(
638        self,
639        class: jclass,
640        method: jmethodID,
641        args: *const jvalue,
642    ) -> Result<jdouble, Local<'env, E>> {
643        let result = ((**self.env).v1_2.CallStaticDoubleMethodA)(self.env, class, method, args);
644        self.exception_check()?;
645        Ok(result)
646    }
647
648    pub unsafe fn call_static_void_method_a<E: ThrowableType>(
649        self,
650        class: jclass,
651        method: jmethodID,
652        args: *const jvalue,
653    ) -> Result<(), Local<'env, E>> {
654        ((**self.env).v1_2.CallStaticVoidMethodA)(self.env, class, method, args);
655        self.exception_check()
656    }
657
658    // Instance Fields
659
660    pub unsafe fn get_object_field<R: ReferenceType>(
661        self,
662        this: jobject,
663        field: jfieldID,
664    ) -> Option<Local<'env, R>> {
665        let result = ((**self.env).v1_2.GetObjectField)(self.env, this, field);
666        if result.is_null() {
667            None
668        } else {
669            Some(Local::from_raw(self, result))
670        }
671    }
672
673    pub unsafe fn get_boolean_field(self, this: jobject, field: jfieldID) -> bool {
674        let result = ((**self.env).v1_2.GetBooleanField)(self.env, this, field);
675        result != JNI_FALSE
676    }
677
678    pub unsafe fn get_byte_field(self, this: jobject, field: jfieldID) -> jbyte {
679        ((**self.env).v1_2.GetByteField)(self.env, this, field)
680    }
681
682    pub unsafe fn get_char_field(self, this: jobject, field: jfieldID) -> jchar {
683        ((**self.env).v1_2.GetCharField)(self.env, this, field)
684    }
685
686    pub unsafe fn get_short_field(self, this: jobject, field: jfieldID) -> jshort {
687        ((**self.env).v1_2.GetShortField)(self.env, this, field)
688    }
689
690    pub unsafe fn get_int_field(self, this: jobject, field: jfieldID) -> jint {
691        ((**self.env).v1_2.GetIntField)(self.env, this, field)
692    }
693
694    pub unsafe fn get_long_field(self, this: jobject, field: jfieldID) -> jlong {
695        ((**self.env).v1_2.GetLongField)(self.env, this, field)
696    }
697
698    pub unsafe fn get_float_field(self, this: jobject, field: jfieldID) -> jfloat {
699        ((**self.env).v1_2.GetFloatField)(self.env, this, field)
700    }
701
702    pub unsafe fn get_double_field(self, this: jobject, field: jfieldID) -> jdouble {
703        ((**self.env).v1_2.GetDoubleField)(self.env, this, field)
704    }
705
706    pub unsafe fn set_object_field<R: ReferenceType>(
707        self,
708        this: jobject,
709        field: jfieldID,
710        value: impl AsArg<R>,
711    ) {
712        ((**self.env).v1_2.SetObjectField)(self.env, this, field, value.as_arg());
713    }
714
715    pub unsafe fn set_boolean_field(self, this: jobject, field: jfieldID, value: bool) {
716        ((**self.env).v1_2.SetBooleanField)(
717            self.env,
718            this,
719            field,
720            if value { JNI_TRUE } else { JNI_FALSE },
721        );
722    }
723
724    pub unsafe fn set_byte_field(self, this: jobject, field: jfieldID, value: jbyte) {
725        ((**self.env).v1_2.SetByteField)(self.env, this, field, value);
726    }
727
728    pub unsafe fn set_char_field(self, this: jobject, field: jfieldID, value: jchar) {
729        ((**self.env).v1_2.SetCharField)(self.env, this, field, value);
730    }
731
732    pub unsafe fn set_short_field(self, this: jobject, field: jfieldID, value: jshort) {
733        ((**self.env).v1_2.SetShortField)(self.env, this, field, value);
734    }
735
736    pub unsafe fn set_int_field(self, this: jobject, field: jfieldID, value: jint) {
737        ((**self.env).v1_2.SetIntField)(self.env, this, field, value);
738    }
739
740    pub unsafe fn set_long_field(self, this: jobject, field: jfieldID, value: jlong) {
741        ((**self.env).v1_2.SetLongField)(self.env, this, field, value);
742    }
743
744    pub unsafe fn set_float_field(self, this: jobject, field: jfieldID, value: jfloat) {
745        ((**self.env).v1_2.SetFloatField)(self.env, this, field, value);
746    }
747
748    pub unsafe fn set_double_field(self, this: jobject, field: jfieldID, value: jdouble) {
749        ((**self.env).v1_2.SetDoubleField)(self.env, this, field, value);
750    }
751
752    // Static Fields
753
754    pub unsafe fn get_static_object_field<R: ReferenceType>(
755        self,
756        class: jclass,
757        field: jfieldID,
758    ) -> Option<Local<'env, R>> {
759        let result = ((**self.env).v1_2.GetStaticObjectField)(self.env, class, field);
760        if result.is_null() {
761            None
762        } else {
763            Some(Local::from_raw(self, result))
764        }
765    }
766
767    pub unsafe fn get_static_boolean_field(self, class: jclass, field: jfieldID) -> bool {
768        let result = ((**self.env).v1_2.GetStaticBooleanField)(self.env, class, field);
769        result != JNI_FALSE
770    }
771
772    pub unsafe fn get_static_byte_field(self, class: jclass, field: jfieldID) -> jbyte {
773        ((**self.env).v1_2.GetStaticByteField)(self.env, class, field)
774    }
775
776    pub unsafe fn get_static_char_field(self, class: jclass, field: jfieldID) -> jchar {
777        ((**self.env).v1_2.GetStaticCharField)(self.env, class, field)
778    }
779
780    pub unsafe fn get_static_short_field(self, class: jclass, field: jfieldID) -> jshort {
781        ((**self.env).v1_2.GetStaticShortField)(self.env, class, field)
782    }
783
784    pub unsafe fn get_static_int_field(self, class: jclass, field: jfieldID) -> jint {
785        ((**self.env).v1_2.GetStaticIntField)(self.env, class, field)
786    }
787
788    pub unsafe fn get_static_long_field(self, class: jclass, field: jfieldID) -> jlong {
789        ((**self.env).v1_2.GetStaticLongField)(self.env, class, field)
790    }
791
792    pub unsafe fn get_static_float_field(self, class: jclass, field: jfieldID) -> jfloat {
793        ((**self.env).v1_2.GetStaticFloatField)(self.env, class, field)
794    }
795
796    pub unsafe fn get_static_double_field(self, class: jclass, field: jfieldID) -> jdouble {
797        ((**self.env).v1_2.GetStaticDoubleField)(self.env, class, field)
798    }
799
800    pub unsafe fn set_static_object_field<R: ReferenceType>(
801        self,
802        class: jclass,
803        field: jfieldID,
804        value: impl AsArg<R>,
805    ) {
806        ((**self.env).v1_2.SetStaticObjectField)(self.env, class, field, value.as_arg());
807    }
808
809    pub unsafe fn set_static_boolean_field(self, class: jclass, field: jfieldID, value: bool) {
810        ((**self.env).v1_2.SetStaticBooleanField)(
811            self.env,
812            class,
813            field,
814            if value { JNI_TRUE } else { JNI_FALSE },
815        );
816    }
817
818    pub unsafe fn set_static_byte_field(self, class: jclass, field: jfieldID, value: jbyte) {
819        ((**self.env).v1_2.SetStaticByteField)(self.env, class, field, value);
820    }
821
822    pub unsafe fn set_static_char_field(self, class: jclass, field: jfieldID, value: jchar) {
823        ((**self.env).v1_2.SetStaticCharField)(self.env, class, field, value);
824    }
825
826    pub unsafe fn set_static_short_field(self, class: jclass, field: jfieldID, value: jshort) {
827        ((**self.env).v1_2.SetStaticShortField)(self.env, class, field, value);
828    }
829
830    pub unsafe fn set_static_int_field(self, class: jclass, field: jfieldID, value: jint) {
831        ((**self.env).v1_2.SetStaticIntField)(self.env, class, field, value);
832    }
833
834    pub unsafe fn set_static_long_field(self, class: jclass, field: jfieldID, value: jlong) {
835        ((**self.env).v1_2.SetStaticLongField)(self.env, class, field, value);
836    }
837
838    pub unsafe fn set_static_float_field(self, class: jclass, field: jfieldID, value: jfloat) {
839        ((**self.env).v1_2.SetStaticFloatField)(self.env, class, field, value);
840    }
841
842    pub unsafe fn set_static_double_field(self, class: jclass, field: jfieldID, value: jdouble) {
843        ((**self.env).v1_2.SetStaticDoubleField)(self.env, class, field, value);
844    }
845
846    pub fn throw<T: ReferenceType>(self, throwable: &Ref<T>) {
847        let res = unsafe { ((**self.env).v1_2.Throw)(self.env, throwable.as_raw()) };
848        assert_eq!(res, 0);
849    }
850}