rust_jni/jni/
throwable.rs

1use jni::class::Class;
2use jni::method_calls::call_constructor;
3use jni::method_calls::call_method;
4use jni::string::String;
5use jni::*;
6use jni_sys;
7use std::fmt;
8
9include!("call_jni_method.rs");
10include!("generate_class.rs");
11
12/// A type representing a Java
13/// [`Throwable`](https://docs.oracle.com/javase/10/docs/api/java/lang/Throwable.html).
14// TODO: examples.
15// TODO: custom debug.
16#[derive(Debug)]
17pub struct Throwable<'env> {
18    object: Object<'env>,
19}
20
21impl<'env> Throwable<'env> {
22    /// Throw the exception. Transfers ownership of the object to Java.
23    ///
24    /// [JNI documentation](https://docs.oracle.com/javase/10/docs/specs/jni/functions.html#throw)
25    pub fn throw(self, token: NoException) -> Exception<'env> {
26        // Safe because the argument is ensured to be correct references by construction.
27        let status = unsafe {
28            call_jni_method!(self.env(), Throw, self.raw_object() as jni_sys::jthrowable)
29        };
30        // Can't really handle failing throwing an exception.
31        if status != jni_sys::JNI_OK {
32            panic!("Throwing an exception has failed with status {}.", status);
33        }
34        // Safe becuase we just threw the exception.
35        unsafe { Exception::new(self.env(), token) }
36    }
37}
38
39java_class!(
40    Throwable,
41    "[`Throwable`](struct.Throwable.html)",
42    constructors = (
43        doc = "Create a new [`Throwable`](struct.Throwable.html) with a message.",
44        link = "[`Throwable(String)` javadoc](https://docs.oracle.com/javase/10/docs/api/java/lang/Throwable.html#<init>(java.lang.String))",
45        new(message: &String<'env>),
46    ),
47    methods = (
48        doc = "Get the exception message.",
49        link = "[`Throwable::getMessage` javadoc](https://docs.oracle.com/javase/10/docs/api/java/lang/Throwable.html#getMessage()).",
50        java_name = "getMessage",
51        get_message() -> String<'env>,
52    ),
53    static_methods = (),
54);
55
56#[cfg(test)]
57pub fn test_throwable<'env>(
58    env: &'env JniEnv<'env>,
59    raw_object: jni_sys::jobject,
60) -> Throwable<'env> {
61    Throwable {
62        object: test_object(env, raw_object),
63    }
64}
65
66#[cfg(test)]
67mod throwable_tests {
68    use super::*;
69    use jni::testing::*;
70    use std::mem;
71    use std::ops::Deref;
72    use std::ptr;
73
74    fn test_value<'env>(env: &'env JniEnv<'env>, raw_object: jni_sys::jobject) -> Throwable<'env> {
75        test_throwable(env, raw_object)
76    }
77
78    generate_tests!(Throwable, "Ljava/lang/Throwable;");
79
80    #[test]
81    fn throw() {
82        const RAW_OBJECT: jni_sys::jobject = 0x91011 as jni_sys::jobject;
83        let calls = test_raw_jni_env!(vec![JniCall::Throw(Throw {
84            object: RAW_OBJECT,
85            result: jni_sys::JNI_OK,
86        })]);
87        let vm = test_vm(ptr::null_mut());
88        let env = test_env(&vm, calls.env);
89        let object = test_value(&env, RAW_OBJECT);
90        object.throw(NoException::test());
91    }
92
93    #[test]
94    #[should_panic(expected = "Throwing an exception has failed with status -1.")]
95    fn throw_failed() {
96        const RAW_OBJECT: jni_sys::jobject = 0x91011 as jni_sys::jobject;
97        let calls = test_raw_jni_env!(vec![JniCall::Throw(Throw {
98            object: RAW_OBJECT,
99            result: jni_sys::JNI_ERR,
100        })]);
101        let vm = test_vm(ptr::null_mut());
102        let env = test_env(&vm, calls.env);
103        let object = test_value(&env, RAW_OBJECT);
104        object.throw(NoException::test());
105    }
106}