java_spaghetti/
env.rs

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