xref: /aosp_15_r20/external/libtextclassifier/native/utils/java/jni-helper.h (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // Utility class that provides similar calls like JNIEnv, but performs
18 // additional checks on them, so that it's harder to use them incorrectly.
19 
20 #ifndef LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_
21 #define LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_
22 
23 #include <jni.h>
24 
25 #include <string>
26 
27 #include "utils/base/status.h"
28 #include "utils/base/statusor.h"
29 #include "utils/java/jni-base.h"
30 
31 #define TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN             \
32   if (!EnsureLocalCapacity(env, 1)) {                   \
33     TC3_LOG(ERROR) << "EnsureLocalCapacity(1) failed."; \
34     return {Status::UNKNOWN};                           \
35   }
36 
37 #define TC3_NO_EXCEPTION_OR_RETURN      \
38   if (JniExceptionCheckAndClear(env)) { \
39     return {Status::UNKNOWN};           \
40   }
41 
42 #define TC3_NOT_NULL_OR_RETURN \
43   if (result == nullptr) {     \
44     return {Status::UNKNOWN};  \
45   }
46 
47 #define TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(                   \
48     METHOD_NAME, RETURN_TYPE, INPUT_TYPE, POST_CHECK)                      \
49   template <typename T = RETURN_TYPE>                                      \
50   static StatusOr<ScopedLocalRef<T>> METHOD_NAME(                          \
51       JNIEnv* env, INPUT_TYPE object, jmethodID method_id, ...) {          \
52     TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN;                                   \
53                                                                            \
54     va_list args;                                                          \
55     va_start(args, method_id);                                             \
56     ScopedLocalRef<T> result(                                              \
57         reinterpret_cast<T>(env->METHOD_NAME##V(object, method_id, args)), \
58         env);                                                              \
59     POST_CHECK                                                             \
60     va_end(args);                                                          \
61                                                                            \
62     TC3_NO_EXCEPTION_OR_RETURN;                                            \
63     return result;                                                         \
64   }
65 
66 #define TC3_JNI_NO_CHECK \
67   {}
68 
69 namespace libtextclassifier3 {
70 
71 class JniHelper {
72  public:
73   // Misc methods.
74   static StatusOr<ScopedLocalRef<jclass>> FindClass(JNIEnv* env,
75                                                     const char* class_name);
76 
77   static StatusOr<ScopedLocalRef<jclass>> GetObjectClass(JNIEnv* env,
78                                                          jobject object);
79 
80   template <typename T = jobject>
81   static StatusOr<ScopedLocalRef<T>> GetObjectArrayElement(JNIEnv* env,
82                                                            jobjectArray array,
83                                                            jsize index);
84   static StatusOr<jmethodID> GetMethodID(JNIEnv* env, jclass clazz,
85                                          const char* method_name,
86                                          const char* signature);
87   static StatusOr<jmethodID> GetStaticMethodID(JNIEnv* env, jclass clazz,
88                                                const char* method_name,
89                                                const char* signature);
90 
91   static StatusOr<jfieldID> GetFieldID(JNIEnv* env, jclass clazz,
92                                        const char* field_name,
93                                        const char* signature);
94   static StatusOr<jfieldID> GetStaticFieldID(JNIEnv* env, jclass clazz,
95                                              const char* field_name,
96                                              const char* signature);
97 
98   static StatusOr<ScopedLocalRef<jobject>> GetStaticObjectField(
99       JNIEnv* env, jclass class_name, jfieldID field_id);
100   static StatusOr<jint> GetStaticIntField(JNIEnv* env, jclass class_name,
101                                           jfieldID field_id);
102 
103   // New* methods.
104   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(NewObject, jobject, jclass,
105                                                   TC3_NOT_NULL_OR_RETURN);
106   static StatusOr<ScopedLocalRef<jobjectArray>> NewObjectArray(
107       JNIEnv* env, jsize length, jclass element_class,
108       jobject initial_element = nullptr);
109   static StatusOr<ScopedLocalRef<jbyteArray>> NewByteArray(JNIEnv* env,
110                                                            jsize length);
111   static StatusOr<ScopedLocalRef<jintArray>> NewIntArray(JNIEnv* env,
112                                                          jsize length);
113   static StatusOr<ScopedLocalRef<jstring>> NewStringUTF(JNIEnv* env,
114                                                         const char* bytes);
115   static StatusOr<ScopedLocalRef<jfloatArray>> NewFloatArray(JNIEnv* env,
116                                                              jsize length);
117 
118   static StatusOr<jsize> GetArrayLength(JNIEnv* env, jarray array);
119 
120   static Status SetObjectArrayElement(JNIEnv* env, jobjectArray array,
121                                       jsize index, jobject val);
122 
123   static Status GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start,
124                                    jsize len, jbyte* buf);
125 
126   static Status SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start,
127                                    jsize len, const jbyte* buf);
128 
129   static Status SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start,
130                                   jsize len, const jint* buf);
131 
132   static Status SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start,
133                                     jsize len, const jfloat* buf);
134 
135   // Call* methods.
136   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallObjectMethod, jobject,
137                                                   jobject, TC3_JNI_NO_CHECK);
138   TC3_DEFINE_VARIADIC_SCOPED_LOCAL_REF_ENV_METHOD(CallStaticObjectMethod,
139                                                   jobject, jclass,
140                                                   TC3_JNI_NO_CHECK);
141   static Status CallVoidMethod(JNIEnv* env, jobject object, jmethodID method_id,
142                                ...);
143   static StatusOr<bool> CallBooleanMethod(JNIEnv* env, jobject object,
144                                           jmethodID method_id, ...);
145   static StatusOr<int32> CallIntMethod(JNIEnv* env, jobject object,
146                                        jmethodID method_id, ...);
147   static StatusOr<int64> CallLongMethod(JNIEnv* env, jobject object,
148                                         jmethodID method_id, ...);
149   static StatusOr<float> CallFloatMethod(JNIEnv* env, jobject object,
150                                          jmethodID method_id, ...);
151   static StatusOr<double> CallDoubleMethod(JNIEnv* env, jobject object,
152                                            jmethodID method_id, ...);
153 
154   template <class T>
155   static StatusOr<T> CallStaticIntMethod(JNIEnv* env,
156                                          bool print_exception_on_error,
157                                          jclass clazz, jmethodID method_id,
158                                          ...);
159 };
160 
161 template <typename T>
GetObjectArrayElement(JNIEnv * env,jobjectArray array,jsize index)162 StatusOr<ScopedLocalRef<T>> JniHelper::GetObjectArrayElement(JNIEnv* env,
163                                                              jobjectArray array,
164                                                              jsize index) {
165   TC3_ENSURE_LOCAL_CAPACITY_OR_RETURN;
166   ScopedLocalRef<T> result(
167       reinterpret_cast<T>(env->GetObjectArrayElement(array, index)), env);
168 
169   TC3_NO_EXCEPTION_OR_RETURN;
170   return result;
171 }
172 
173 template <class T>
CallStaticIntMethod(JNIEnv * env,bool print_exception_on_error,jclass clazz,jmethodID method_id,...)174 StatusOr<T> JniHelper::CallStaticIntMethod(JNIEnv* env,
175                                            bool print_exception_on_error,
176                                            jclass clazz, jmethodID method_id,
177                                            ...) {
178   va_list args;
179   va_start(args, method_id);
180   jint result = env->CallStaticIntMethodV(clazz, method_id, args);
181   va_end(args);
182 
183   if (JniExceptionCheckAndClear(env, print_exception_on_error)) {
184     return {Status::UNKNOWN};
185   }
186 
187   return result;
188 }
189 
190 // Converts Java byte[] object to std::string.
191 StatusOr<std::string> JByteArrayToString(JNIEnv* env, jbyteArray array);
192 
193 // Converts Java String object to UTF8-encoded std::string.
194 StatusOr<std::string> JStringToUtf8String(JNIEnv* env, jstring jstr);
195 
196 }  // namespace libtextclassifier3
197 
198 #endif  // LIBTEXTCLASSIFIER_UTILS_JAVA_JNI_HELPER_H_
199