You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
14 KiB
315 lines
14 KiB
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "utils/java/jni-cache.h"
|
|
|
|
#include "utils/base/logging.h"
|
|
#include "utils/base/status_macros.h"
|
|
#include "utils/java/jni-base.h"
|
|
#include "utils/java/jni-helper.h"
|
|
|
|
namespace libtextclassifier3 {
|
|
|
|
JniCache::JniCache(JavaVM* jvm)
|
|
: jvm(jvm),
|
|
string_class(nullptr, jvm),
|
|
string_utf8(nullptr, jvm),
|
|
pattern_class(nullptr, jvm),
|
|
matcher_class(nullptr, jvm),
|
|
locale_class(nullptr, jvm),
|
|
locale_us(nullptr, jvm),
|
|
breakiterator_class(nullptr, jvm),
|
|
integer_class(nullptr, jvm),
|
|
calendar_class(nullptr, jvm),
|
|
timezone_class(nullptr, jvm)
|
|
#ifdef __ANDROID__
|
|
,
|
|
context_class(nullptr, jvm),
|
|
uri_class(nullptr, jvm),
|
|
usermanager_class(nullptr, jvm),
|
|
bundle_class(nullptr, jvm),
|
|
resources_class(nullptr, jvm)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
// The macros below are intended to reduce the boilerplate in Create and avoid
|
|
// easily introduced copy/paste errors.
|
|
#define TC3_CHECK_JNI_PTR(PTR) TC3_CHECK((PTR) != nullptr)
|
|
#define TC3_CHECK_JNI_RESULT(RESULT) TC3_CHECK(RESULT)
|
|
|
|
#define TC3_GET_CLASS_OR_RETURN_NULL(FIELD, NAME) \
|
|
{ \
|
|
TC3_ASSIGN_OR_RETURN_NULL(ScopedLocalRef<jclass> clazz, \
|
|
JniHelper::FindClass(env, NAME)); \
|
|
result->FIELD##_class = MakeGlobalRef(clazz.get(), env, jvm); \
|
|
if (result->FIELD##_class == nullptr) { \
|
|
TC3_LOG(ERROR) << "Error finding class: " << NAME; \
|
|
return nullptr; \
|
|
} \
|
|
}
|
|
|
|
#define TC3_GET_OPTIONAL_CLASS(FIELD, NAME) \
|
|
{ \
|
|
StatusOr<ScopedLocalRef<jclass>> status_or_class = \
|
|
JniHelper::FindClass(env, NAME); \
|
|
if (status_or_class.ok()) { \
|
|
result->FIELD##_class = MakeGlobalRef( \
|
|
std::move(status_or_class).ValueOrDie().get(), env, jvm); \
|
|
} \
|
|
}
|
|
|
|
#define TC3_GET_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
|
|
TC3_ASSIGN_OR_RETURN_NULL( \
|
|
result->CLASS##_##FIELD, \
|
|
JniHelper::GetMethodID(env, result->CLASS##_class.get(), NAME, \
|
|
SIGNATURE));
|
|
|
|
#define TC3_GET_OPTIONAL_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
|
|
TC3_GET_OPTIONAL_METHOD_INTERNAL(CLASS, FIELD, NAME, SIGNATURE, GetMethodID)
|
|
|
|
#define TC3_GET_OPTIONAL_STATIC_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
|
|
TC3_GET_OPTIONAL_METHOD_INTERNAL(CLASS, FIELD, NAME, SIGNATURE, \
|
|
GetStaticMethodID)
|
|
|
|
#define TC3_GET_OPTIONAL_METHOD_INTERNAL(CLASS, FIELD, NAME, SIGNATURE, \
|
|
METHOD_NAME) \
|
|
if (result->CLASS##_class != nullptr) { \
|
|
if (StatusOr<jmethodID> status_or_method_id = JniHelper::METHOD_NAME( \
|
|
env, result->CLASS##_class.get(), NAME, SIGNATURE); \
|
|
status_or_method_id.ok()) { \
|
|
result->CLASS##_##FIELD = status_or_method_id.ValueOrDie(); \
|
|
} \
|
|
}
|
|
|
|
#define TC3_GET_STATIC_METHOD(CLASS, FIELD, NAME, SIGNATURE) \
|
|
TC3_ASSIGN_OR_RETURN_NULL( \
|
|
result->CLASS##_##FIELD, \
|
|
JniHelper::GetStaticMethodID(env, result->CLASS##_class.get(), NAME, \
|
|
SIGNATURE));
|
|
|
|
#define TC3_GET_STATIC_OBJECT_FIELD_OR_RETURN_NULL(CLASS, FIELD, NAME, \
|
|
SIGNATURE) \
|
|
{ \
|
|
TC3_ASSIGN_OR_RETURN_NULL( \
|
|
const jfieldID CLASS##_##FIELD##_field, \
|
|
JniHelper::GetStaticFieldID(env, result->CLASS##_class.get(), NAME, \
|
|
SIGNATURE)); \
|
|
TC3_ASSIGN_OR_RETURN_NULL( \
|
|
ScopedLocalRef<jobject> static_object, \
|
|
JniHelper::GetStaticObjectField(env, result->CLASS##_class.get(), \
|
|
CLASS##_##FIELD##_field)); \
|
|
result->CLASS##_##FIELD = MakeGlobalRef(static_object.get(), env, jvm); \
|
|
if (result->CLASS##_##FIELD == nullptr) { \
|
|
TC3_LOG(ERROR) << "Error finding field: " << NAME; \
|
|
return nullptr; \
|
|
} \
|
|
}
|
|
|
|
#define TC3_GET_STATIC_INT_FIELD(CLASS, FIELD, NAME) \
|
|
TC3_ASSIGN_OR_RETURN_NULL(const jfieldID CLASS##_##FIELD##_field, \
|
|
JniHelper::GetStaticFieldID( \
|
|
env, result->CLASS##_class.get(), NAME, "I")); \
|
|
TC3_ASSIGN_OR_RETURN_NULL( \
|
|
result->CLASS##_##FIELD, \
|
|
JniHelper::GetStaticIntField(env, result->CLASS##_class.get(), \
|
|
CLASS##_##FIELD##_field));
|
|
|
|
std::unique_ptr<JniCache> JniCache::Create(JNIEnv* env) {
|
|
if (env == nullptr) {
|
|
return nullptr;
|
|
}
|
|
JavaVM* jvm = nullptr;
|
|
if (JNI_OK != env->GetJavaVM(&jvm) || jvm == nullptr) {
|
|
return nullptr;
|
|
}
|
|
std::unique_ptr<JniCache> result(new JniCache(jvm));
|
|
|
|
// String
|
|
TC3_GET_CLASS_OR_RETURN_NULL(string, "java/lang/String");
|
|
TC3_GET_METHOD(string, init_bytes_charset, "<init>",
|
|
"([BLjava/lang/String;)V");
|
|
TC3_GET_METHOD(string, code_point_count, "codePointCount", "(II)I");
|
|
TC3_GET_METHOD(string, length, "length", "()I");
|
|
TC3_ASSIGN_OR_RETURN_NULL(ScopedLocalRef<jstring> result_string,
|
|
JniHelper::NewStringUTF(env, "UTF-8"));
|
|
result->string_utf8 = MakeGlobalRef(result_string.get(), env, jvm);
|
|
TC3_CHECK_JNI_PTR(result->string_utf8);
|
|
|
|
// Pattern
|
|
TC3_GET_CLASS_OR_RETURN_NULL(pattern, "java/util/regex/Pattern");
|
|
TC3_GET_STATIC_METHOD(pattern, compile, "compile",
|
|
"(Ljava/lang/String;)Ljava/util/regex/Pattern;");
|
|
TC3_GET_METHOD(pattern, matcher, "matcher",
|
|
"(Ljava/lang/CharSequence;)Ljava/util/regex/Matcher;");
|
|
|
|
// Matcher
|
|
TC3_GET_CLASS_OR_RETURN_NULL(matcher, "java/util/regex/Matcher");
|
|
TC3_GET_METHOD(matcher, matches, "matches", "()Z");
|
|
TC3_GET_METHOD(matcher, find, "find", "()Z");
|
|
TC3_GET_METHOD(matcher, reset, "reset", "()Ljava/util/regex/Matcher;");
|
|
TC3_GET_METHOD(matcher, start_idx, "start", "(I)I");
|
|
TC3_GET_METHOD(matcher, end_idx, "end", "(I)I");
|
|
TC3_GET_METHOD(matcher, group, "group", "()Ljava/lang/String;");
|
|
TC3_GET_METHOD(matcher, group_idx, "group", "(I)Ljava/lang/String;");
|
|
|
|
// Locale
|
|
TC3_GET_CLASS_OR_RETURN_NULL(locale, "java/util/Locale");
|
|
TC3_GET_STATIC_OBJECT_FIELD_OR_RETURN_NULL(locale, us, "US",
|
|
"Ljava/util/Locale;");
|
|
TC3_GET_METHOD(locale, init_string, "<init>", "(Ljava/lang/String;)V");
|
|
TC3_GET_OPTIONAL_STATIC_METHOD(locale, for_language_tag, "forLanguageTag",
|
|
"(Ljava/lang/String;)Ljava/util/Locale;");
|
|
|
|
// BreakIterator
|
|
TC3_GET_CLASS_OR_RETURN_NULL(breakiterator, "java/text/BreakIterator");
|
|
TC3_GET_STATIC_METHOD(breakiterator, getwordinstance, "getWordInstance",
|
|
"(Ljava/util/Locale;)Ljava/text/BreakIterator;");
|
|
TC3_GET_METHOD(breakiterator, settext, "setText", "(Ljava/lang/String;)V");
|
|
TC3_GET_METHOD(breakiterator, next, "next", "()I");
|
|
|
|
// Integer
|
|
TC3_GET_CLASS_OR_RETURN_NULL(integer, "java/lang/Integer");
|
|
TC3_GET_STATIC_METHOD(integer, parse_int, "parseInt",
|
|
"(Ljava/lang/String;)I");
|
|
|
|
// Calendar.
|
|
TC3_GET_CLASS_OR_RETURN_NULL(calendar, "java/util/Calendar");
|
|
TC3_GET_STATIC_METHOD(
|
|
calendar, get_instance, "getInstance",
|
|
"(Ljava/util/TimeZone;Ljava/util/Locale;)Ljava/util/Calendar;");
|
|
TC3_GET_METHOD(calendar, get_first_day_of_week, "getFirstDayOfWeek", "()I");
|
|
TC3_GET_METHOD(calendar, get_time_in_millis, "getTimeInMillis", "()J");
|
|
TC3_GET_METHOD(calendar, set_time_in_millis, "setTimeInMillis", "(J)V");
|
|
TC3_GET_METHOD(calendar, add, "add", "(II)V");
|
|
TC3_GET_METHOD(calendar, get, "get", "(I)I");
|
|
TC3_GET_METHOD(calendar, set, "set", "(II)V");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, zone_offset, "ZONE_OFFSET");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, dst_offset, "DST_OFFSET");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, year, "YEAR");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, month, "MONTH");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, day_of_year, "DAY_OF_YEAR");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, day_of_month, "DAY_OF_MONTH");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, day_of_week, "DAY_OF_WEEK");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, hour_of_day, "HOUR_OF_DAY");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, minute, "MINUTE");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, second, "SECOND");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, millisecond, "MILLISECOND");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, sunday, "SUNDAY");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, monday, "MONDAY");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, tuesday, "TUESDAY");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, wednesday, "WEDNESDAY");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, thursday, "THURSDAY");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, friday, "FRIDAY");
|
|
TC3_GET_STATIC_INT_FIELD(calendar, saturday, "SATURDAY");
|
|
|
|
// TimeZone.
|
|
TC3_GET_CLASS_OR_RETURN_NULL(timezone, "java/util/TimeZone");
|
|
TC3_GET_STATIC_METHOD(timezone, get_timezone, "getTimeZone",
|
|
"(Ljava/lang/String;)Ljava/util/TimeZone;");
|
|
|
|
#ifdef __ANDROID__
|
|
// Context.
|
|
TC3_GET_CLASS_OR_RETURN_NULL(context, "android/content/Context");
|
|
TC3_GET_METHOD(context, get_package_name, "getPackageName",
|
|
"()Ljava/lang/String;");
|
|
TC3_GET_METHOD(context, get_system_service, "getSystemService",
|
|
"(Ljava/lang/String;)Ljava/lang/Object;");
|
|
|
|
// Uri.
|
|
TC3_GET_CLASS_OR_RETURN_NULL(uri, "android/net/Uri");
|
|
TC3_GET_STATIC_METHOD(uri, parse, "parse",
|
|
"(Ljava/lang/String;)Landroid/net/Uri;");
|
|
TC3_GET_METHOD(uri, get_scheme, "getScheme", "()Ljava/lang/String;");
|
|
TC3_GET_METHOD(uri, get_host, "getHost", "()Ljava/lang/String;");
|
|
TC3_GET_STATIC_METHOD(uri, encode, "encode",
|
|
"(Ljava/lang/String;)Ljava/lang/String;");
|
|
|
|
// UserManager.
|
|
TC3_GET_OPTIONAL_CLASS(usermanager, "android/os/UserManager");
|
|
TC3_GET_OPTIONAL_METHOD(usermanager, get_user_restrictions,
|
|
"getUserRestrictions", "()Landroid/os/Bundle;");
|
|
|
|
// Bundle.
|
|
TC3_GET_CLASS_OR_RETURN_NULL(bundle, "android/os/Bundle");
|
|
TC3_GET_METHOD(bundle, get_boolean, "getBoolean", "(Ljava/lang/String;)Z");
|
|
|
|
// String resources.
|
|
TC3_GET_CLASS_OR_RETURN_NULL(resources, "android/content/res/Resources");
|
|
TC3_GET_STATIC_METHOD(resources, get_system, "getSystem",
|
|
"()Landroid/content/res/Resources;");
|
|
TC3_GET_METHOD(resources, get_identifier, "getIdentifier",
|
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I");
|
|
TC3_GET_METHOD(resources, get_string, "getString", "(I)Ljava/lang/String;");
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
#undef TC3_GET_STATIC_INT_FIELD
|
|
#undef TC3_GET_STATIC_OBJECT_FIELD_OR_RETURN_NULL
|
|
#undef TC3_GET_STATIC_METHOD
|
|
#undef TC3_GET_METHOD
|
|
#undef TC3_GET_CLASS_OR_RETURN_NULL
|
|
#undef TC3_GET_OPTIONAL_CLASS
|
|
#undef TC3_CHECK_JNI_PTR
|
|
|
|
JNIEnv* JniCache::GetEnv() const {
|
|
void* env;
|
|
if (JNI_OK == jvm->GetEnv(&env, JNI_VERSION_1_4)) {
|
|
return reinterpret_cast<JNIEnv*>(env);
|
|
} else {
|
|
TC3_LOG(ERROR) << "JavaICU UniLib used on unattached thread";
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
bool JniCache::ExceptionCheckAndClear() const {
|
|
return JniExceptionCheckAndClear(GetEnv());
|
|
}
|
|
|
|
StatusOr<ScopedLocalRef<jstring>> JniCache::ConvertToJavaString(
|
|
const char* utf8_text, const int utf8_text_size_bytes) const {
|
|
// Create java byte array.
|
|
JNIEnv* jenv = GetEnv();
|
|
TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jbyteArray> text_java_utf8,
|
|
JniHelper::NewByteArray(jenv, utf8_text_size_bytes));
|
|
|
|
TC3_RETURN_IF_ERROR(JniHelper::SetByteArrayRegion(
|
|
jenv, text_java_utf8.get(), 0, utf8_text_size_bytes,
|
|
reinterpret_cast<const jbyte*>(utf8_text)));
|
|
|
|
// Create the string with a UTF-8 charset.
|
|
TC3_ASSIGN_OR_RETURN(ScopedLocalRef<jstring> result,
|
|
JniHelper::NewObject<jstring>(
|
|
jenv, string_class.get(), string_init_bytes_charset,
|
|
text_java_utf8.get(), string_utf8.get()));
|
|
|
|
return result;
|
|
}
|
|
|
|
StatusOr<ScopedLocalRef<jstring>> JniCache::ConvertToJavaString(
|
|
StringPiece utf8_text) const {
|
|
return ConvertToJavaString(utf8_text.data(), utf8_text.size());
|
|
}
|
|
|
|
StatusOr<ScopedLocalRef<jstring>> JniCache::ConvertToJavaString(
|
|
const UnicodeText& text) const {
|
|
return ConvertToJavaString(text.data(), text.size_bytes());
|
|
}
|
|
|
|
} // namespace libtextclassifier3
|