blob: cd89e5c160fb7d25021184f24acc104e4bfb7ee5 [file] [log] [blame]
Tony Mak6c4cc672018-09-17 11:48:50 +01001/*
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#include "utils/java/jni-cache.h"
18
19#include "utils/base/logging.h"
20
21namespace libtextclassifier3 {
22
23JniCache::JniCache(JavaVM* jvm)
24 : jvm(jvm),
25 string_class(nullptr, jvm),
26 string_utf8(nullptr, jvm),
27 pattern_class(nullptr, jvm),
28 matcher_class(nullptr, jvm),
29 locale_class(nullptr, jvm),
30 locale_us(nullptr, jvm),
31 breakiterator_class(nullptr, jvm),
32 integer_class(nullptr, jvm),
33 calendar_class(nullptr, jvm),
34 timezone_class(nullptr, jvm) {}
35
36// The macros below are intended to reduce the boilerplate in Create and avoid
37// easily introduced copy/paste errors.
38#define TC3_CHECK_JNI_PTR(PTR) \
39 TC3_DCHECK(PTR); \
40 if (!(PTR)) return nullptr;
41
42#define TC3_GET_CLASS(FIELD, NAME) \
43 result->FIELD##_class = MakeGlobalRef(env->FindClass(NAME), env, jvm); \
44 TC3_CHECK_JNI_PTR(result->FIELD##_class)
45
46#define TC3_GET_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
47 result->CLASS##_##FIELD = \
48 env->GetMethodID(result->CLASS##_class.get(), NAME, SIGNATURE); \
49 TC3_CHECK_JNI_PTR(result->CLASS##_##FIELD)
50
51#define TC3_GET_OPTIONAL_STATIC_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
52 result->CLASS##_##FIELD = \
53 env->GetStaticMethodID(result->CLASS##_class.get(), NAME, SIGNATURE); \
54 env->ExceptionClear();
55
56#define TC3_GET_STATIC_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
57 result->CLASS##_##FIELD = \
58 env->GetStaticMethodID(result->CLASS##_class.get(), NAME, SIGNATURE); \
59 TC3_CHECK_JNI_PTR(result->CLASS##_##FIELD)
60
61#define TC3_GET_STATIC_OBJECT_FIELD(CLASS, FIELD, NAME, SIGNATURE) \
62 const jfieldID CLASS##_##FIELD##_field = \
63 env->GetStaticFieldID(result->CLASS##_class.get(), NAME, SIGNATURE); \
64 TC3_CHECK_JNI_PTR(CLASS##_##FIELD##_field) \
65 result->CLASS##_##FIELD = \
66 MakeGlobalRef(env->GetStaticObjectField(result->CLASS##_class.get(), \
67 CLASS##_##FIELD##_field), \
68 env, jvm); \
69 TC3_CHECK_JNI_PTR(result->CLASS##_##FIELD)
70
71#define TC3_GET_STATIC_INT_FIELD(CLASS, FIELD, NAME) \
72 const jfieldID CLASS##_##FIELD##_field = \
73 env->GetStaticFieldID(result->CLASS##_class.get(), NAME, "I"); \
74 TC3_CHECK_JNI_PTR(CLASS##_##FIELD##_field) \
75 result->CLASS##_##FIELD = env->GetStaticIntField( \
76 result->CLASS##_class.get(), CLASS##_##FIELD##_field); \
77 TC3_CHECK_JNI_PTR(result->CLASS##_##FIELD)
78
79std::unique_ptr<JniCache> JniCache::Create(JNIEnv* env) {
80 if (env == nullptr) {
81 return nullptr;
82 }
83 JavaVM* jvm = nullptr;
84 if (JNI_OK != env->GetJavaVM(&jvm) || jvm == nullptr) {
85 return nullptr;
86 }
87 std::unique_ptr<JniCache> result(new JniCache(jvm));
88
89 // String
90 TC3_GET_CLASS(string, "java/lang/String");
91 TC3_GET_METHOD(string, init_bytes_charset, "<init>",
92 "([BLjava/lang/String;)V");
93 TC3_GET_METHOD(string, code_point_count, "codePointCount", "(II)I");
94 TC3_GET_METHOD(string, length, "length", "()I");
95 result->string_utf8 = MakeGlobalRef(env->NewStringUTF("UTF-8"), env, jvm);
96 TC3_CHECK_JNI_PTR(result->string_utf8)
97
98 // Pattern
99 TC3_GET_CLASS(pattern, "java/util/regex/Pattern");
100 TC3_GET_STATIC_METHOD(pattern, compile, "compile",
101 "(Ljava/lang/String;)Ljava/util/regex/Pattern;");
102 TC3_GET_METHOD(pattern, matcher, "matcher",
103 "(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;");
104
105 // Matcher
106 TC3_GET_CLASS(matcher, "java/util/regex/Matcher");
107 TC3_GET_METHOD(matcher, matches, "matches", "()Z");
108 TC3_GET_METHOD(matcher, find, "find", "()Z");
109 TC3_GET_METHOD(matcher, reset, "reset", "()Ljava/util/regex/Matcher;");
110 TC3_GET_METHOD(matcher, start_idx, "start", "(I)I");
111 TC3_GET_METHOD(matcher, end_idx, "end", "(I)I");
112 TC3_GET_METHOD(matcher, group, "group", "()Ljava/lang/String;");
113 TC3_GET_METHOD(matcher, group_idx, "group", "(I)Ljava/lang/String;");
114
115 // Locale
116 TC3_GET_CLASS(locale, "java/util/Locale");
117 TC3_GET_STATIC_OBJECT_FIELD(locale, us, "US", "Ljava/util/Locale;");
118 TC3_GET_METHOD(locale, init_string, "<init>", "(Ljava/lang/String;)V");
119 TC3_GET_OPTIONAL_STATIC_METHOD(locale, for_language_tag, "forLanguageTag",
120 "(Ljava/lang/String;)Ljava/util/Locale;");
121
122 // BreakIterator
123 TC3_GET_CLASS(breakiterator, "java/text/BreakIterator");
124 TC3_GET_STATIC_METHOD(breakiterator, getwordinstance, "getWordInstance",
125 "(Ljava/util/Locale;)Ljava/text/BreakIterator;");
126 TC3_GET_METHOD(breakiterator, settext, "setText", "(Ljava/lang/String;)V");
127 TC3_GET_METHOD(breakiterator, next, "next", "()I");
128
129 // Integer
130 TC3_GET_CLASS(integer, "java/lang/Integer");
131 TC3_GET_STATIC_METHOD(integer, parse_int, "parseInt",
132 "(Ljava/lang/String;)I");
133
134 // Calendar.
135 TC3_GET_CLASS(calendar, "java/util/Calendar");
136 TC3_GET_STATIC_METHOD(
137 calendar, get_instance, "getInstance",
138 "(Ljava/util/TimeZone;Ljava/util/Locale;)Ljava/util/Calendar;");
139 TC3_GET_METHOD(calendar, get_first_day_of_week, "getFirstDayOfWeek", "()I");
140 TC3_GET_METHOD(calendar, get_time_in_millis, "getTimeInMillis", "()J");
141 TC3_GET_METHOD(calendar, set_time_in_millis, "setTimeInMillis", "(J)V");
142 TC3_GET_METHOD(calendar, add, "add", "(II)V");
143 TC3_GET_METHOD(calendar, get, "get", "(I)I");
144 TC3_GET_METHOD(calendar, set, "set", "(II)V");
145 TC3_GET_STATIC_INT_FIELD(calendar, zone_offset, "ZONE_OFFSET");
146 TC3_GET_STATIC_INT_FIELD(calendar, dst_offset, "DST_OFFSET");
147 TC3_GET_STATIC_INT_FIELD(calendar, year, "YEAR");
148 TC3_GET_STATIC_INT_FIELD(calendar, month, "MONTH");
149 TC3_GET_STATIC_INT_FIELD(calendar, day_of_year, "DAY_OF_YEAR");
150 TC3_GET_STATIC_INT_FIELD(calendar, day_of_month, "DAY_OF_MONTH");
151 TC3_GET_STATIC_INT_FIELD(calendar, day_of_week, "DAY_OF_WEEK");
152 TC3_GET_STATIC_INT_FIELD(calendar, hour_of_day, "HOUR_OF_DAY");
153 TC3_GET_STATIC_INT_FIELD(calendar, minute, "MINUTE");
154 TC3_GET_STATIC_INT_FIELD(calendar, second, "SECOND");
155 TC3_GET_STATIC_INT_FIELD(calendar, millisecond, "MILLISECOND");
156 TC3_GET_STATIC_INT_FIELD(calendar, sunday, "SUNDAY");
157 TC3_GET_STATIC_INT_FIELD(calendar, monday, "MONDAY");
158 TC3_GET_STATIC_INT_FIELD(calendar, tuesday, "TUESDAY");
159 TC3_GET_STATIC_INT_FIELD(calendar, wednesday, "WEDNESDAY");
160 TC3_GET_STATIC_INT_FIELD(calendar, thursday, "THURSDAY");
161 TC3_GET_STATIC_INT_FIELD(calendar, friday, "FRIDAY");
162 TC3_GET_STATIC_INT_FIELD(calendar, saturday, "SATURDAY");
163
164 // TimeZone.
165 TC3_GET_CLASS(timezone, "java/util/TimeZone");
166 TC3_GET_STATIC_METHOD(timezone, get_timezone, "getTimeZone",
167 "(Ljava/lang/String;)Ljava/util/TimeZone;");
168
169 return result;
170}
171
172#undef TC3_GET_STATIC_INT_FIELD
173#undef TC3_GET_STATIC_OBJECT_FIELD
174#undef TC3_GET_STATIC_METHOD
175#undef TC3_GET_METHOD
176#undef TC3_GET_CLASS
177#undef TC3_CHECK_JNI_PTR
178
179JNIEnv* JniCache::GetEnv() const {
180 void* env;
181 if (JNI_OK == jvm->GetEnv(&env, JNI_VERSION_1_4)) {
182 return reinterpret_cast<JNIEnv*>(env);
183 } else {
184 TC3_LOG(ERROR) << "JavaICU UniLib used on unattached thread";
185 return nullptr;
186 }
187}
188
189bool JniCache::ExceptionCheckAndClear() const {
190 JNIEnv* env = GetEnv();
191 TC3_CHECK(env != nullptr);
192 const bool result = env->ExceptionCheck();
193 if (result) {
194 env->ExceptionDescribe();
195 env->ExceptionClear();
196 }
197 return result;
198}
199
200ScopedLocalRef<jstring> JniCache::ConvertToJavaString(
201 const UnicodeText& text) const {
202 // Create java byte array.
203 JNIEnv* jenv = GetEnv();
204 const ScopedLocalRef<jbyteArray> text_java_utf8(
205 jenv->NewByteArray(text.size_bytes()), jenv);
206 if (!text_java_utf8) {
207 return nullptr;
208 }
209
210 jenv->SetByteArrayRegion(text_java_utf8.get(), 0, text.size_bytes(),
211 reinterpret_cast<const jbyte*>(text.data()));
212
213 // Create the string with a UTF-8 charset.
214 return ScopedLocalRef<jstring>(
215 reinterpret_cast<jstring>(
216 jenv->NewObject(string_class.get(), string_init_bytes_charset,
217 text_java_utf8.get(), string_utf8.get())),
218 jenv);
219}
220
221} // namespace libtextclassifier3