1 // Copyright 2024 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #![allow(unsafe_code)]
16 
17 use jni::{
18     descriptors::Desc,
19     objects::JObject,
20     signature::{JavaType, Primitive, ReturnType},
21     JavaVM,
22 };
23 use std::error::Error;
24 
25 mod common;
26 use common::foo_class::*;
27 
28 #[test]
jni_access() -> Result<(), Box<dyn Error>>29 fn jni_access() -> Result<(), Box<dyn Error>> {
30     // Create the environment
31     let vm = JavaVM::new(
32         jni::InitArgsBuilder::new()
33             .version(jni::JNIVersion::V8)
34             .option("-Xcheck:jni")
35             .build()?,
36     )?;
37     let mut env = vm.attach_current_thread()?;
38 
39     // Load `Foo.class`
40     {
41         let foo_class = compile_foo()?;
42         let loaded_foo = env.define_class(CLASS_DESC, &JObject::null(), &foo_class)?;
43         let loaded_foo = env.auto_local(loaded_foo);
44 
45         let found_foo = FOO.lookup(&mut env)?;
46         assert!(env.is_same_object(&loaded_foo, found_foo.as_ref())?);
47     }
48 
49     // Verify we can call the constructor
50     let obj_foo = {
51         let method_id = CONSTRUCTOR.lookup(&mut env)?;
52         let args = &[jni::sys::jvalue { i: 123 }];
53         // Safety: `args` must match the constructor arg count and types.
54         unsafe { env.new_object_unchecked(CONSTRUCTOR.cls(), method_id, args) }?
55     };
56     assert!(env.is_instance_of(&obj_foo, &FOO)?);
57 
58     // Verify we can access all of the members
59 
60     let field_value = {
61         env.get_field_unchecked(&obj_foo, &FIELD, ReturnType::Primitive(Primitive::Int))?
62             .i()?
63     };
64     assert_eq!(123, field_value);
65 
66     let method_value = {
67         let method_id = METHOD.lookup(&mut env)?;
68         let args = &[];
69         // Safety: `args` must match the method arg count and types.
70         unsafe {
71             env.call_method_unchecked(
72                 &obj_foo,
73                 method_id,
74                 ReturnType::Primitive(Primitive::Boolean),
75                 args,
76             )
77         }?
78         .z()?
79     };
80     assert!(method_value);
81 
82     env.delete_local_ref(obj_foo)?;
83 
84     let static_field_value = {
85         env.get_static_field_unchecked(&FOO, &STATIC_FIELD, JavaType::Primitive(Primitive::Long))?
86             .j()?
87     };
88     assert_eq!(321, static_field_value);
89 
90     let static_method_value = {
91         let method_id = STATIC_METHOD.lookup(&mut env)?;
92         let args = &[];
93         // Safety: `args` must match the method arg count and types.
94         unsafe {
95             env.call_static_method_unchecked(
96                 &FOO,
97                 method_id,
98                 ReturnType::Primitive(Primitive::Int),
99                 args,
100             )
101         }?
102         .i()?
103     };
104     assert_eq!(3, static_method_value);
105 
106     Ok(())
107 }
108