Improve Java binding.

GitOrigin-RevId: ec10cb32f546a1249f4fe5f309eaff7488c31182
This commit is contained in:
levlam 2018-01-15 16:47:24 +03:00
parent 224de03838
commit 8eb46f6715
7 changed files with 176 additions and 113 deletions

View File

@ -547,6 +547,15 @@ target_include_directories(tdcore PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURC
target_include_directories(tdcore SYSTEM PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(tdcore PUBLIC tdactor tdutils tdnet tddb PRIVATE ${OPENSSL_CRYPTO_LIBRARY})
if (TD_API_JAVA_PACKAGE AND NOT ANDROID) # jni is available by default on Android
if (NOT JNI_FOUND)
find_package(JNI REQUIRED)
endif()
message(STATUS "Found JNI: ${JNI_INCLUDE_DIRS} ${JNI_LIBRARIES}")
target_include_directories(tdcore PUBLIC ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
target_link_libraries(tdcore PUBLIC ${JAVA_JVM_LIBRARY})
endif()
if (NOT CMAKE_CROSSCOMPILING)
add_dependencies(tdcore tl_generate_common)
endif()
@ -558,6 +567,11 @@ target_include_directories(tdclient PUBLIC
)
target_link_libraries(tdclient PRIVATE tdcore)
if (TD_API_JAVA_PACKAGE AND NOT ANDROID) # jni is available by default on Android
target_include_directories(tdclient PUBLIC ${JAVA_INCLUDE_PATH} ${JAVA_INCLUDE_PATH2})
target_link_libraries(tdclient PUBLIC ${JAVA_JVM_LIBRARY})
endif()
# tdc - TDLib interface in pure c.
add_library(tdc STATIC ${TL_C_SCHEME_SOURCE} td/telegram/td_c_client.cpp td/telegram/td_c_client.h)
target_include_directories(tdc PUBLIC
@ -595,13 +609,21 @@ target_link_libraries(tdjson_static PRIVATE tdjson_private)
target_compile_definitions(tdjson_static PUBLIC TDJSON_STATIC_DEFINE)
target_include_directories(tdjson_static PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
set(BIGOBJ)
if (WIN32 OR CYGWIN)
if (MSVC)
target_compile_options(tdcore PUBLIC "/bigobj")
set(BIGOBJ "/bigobj")
elseif (GCC)
target_compile_options(tdcore PUBLIC "-Wa,-mbig-obj")
set(BIGOBJ "-Wa,-mbig-obj")
endif()
endif()
if (BIGOBJ)
target_compile_options(tdc PUBLIC ${BIGOBJ})
target_compile_options(tdcore PUBLIC ${BIGOBJ})
target_compile_options(tdclient PUBLIC ${BIGOBJ})
target_compile_options(tdjson PUBLIC ${BIGOBJ})
target_compile_options(tdjson_static PUBLIC ${BIGOBJ})
endif()
if (EMSCRIPTEN)
set(TD_EMSCRIPTEN_SRC td/telegram/td_emscripten.cpp)
@ -660,6 +682,9 @@ install(FILES ${TD_JSON_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/td/telegram/tdjson_
install(FILES td/telegram/Client.h td/telegram/Log.h DESTINATION include/td/telegram)
install(FILES td/tl/TlObject.h DESTINATION include/td/tl)
install(FILES ${TL_TD_AUTO_INCLUDES}/td/telegram/td_api.h ${TL_TD_AUTO_INCLUDES}/td/telegram/td_api.hpp DESTINATION include/td/telegram)
if (TD_API_JAVA_PACKAGE)
install(FILES td/tl/tl_jni_object.h DESTINATION include/td/tl)
endif()
include(CMakePackageConfigHelpers)
write_basic_package_version_file("TdConfigVersion.cmake"

View File

@ -449,7 +449,7 @@ std::string TD_TL_writer_java::gen_store_function_begin(const std::string &store
" protected " +
storer_name + " appendLine(" + storer_name +
" s, int shift) {\n"
" s.append('\\n');\n"
" s.append(System.lineSeparator());\n"
" for (int i = 0; i < shift; i++) {\n"
" s.append(' ');\n"
" }\n"

View File

@ -77,113 +77,44 @@ std::string TD_TL_writer_jni_cpp::gen_vector_fetch(std::string field_name, const
int parser_type) const {
std::string vector_type = gen_type_name(t);
std::string type;
std::string Type;
if (vector_type == "bool") {
assert(false); // TODO
}
std::string fetch_object = "jni::fetch_object(env, p, " + field_name + "fieldID)";
std::string array_type;
if (vector_type == "std::int32_t") {
type = "int";
Type = "Int";
array_type = "jintArray";
}
if (vector_type == "std::int64_t") {
type = "long";
Type = "Long";
array_type = "jlongArray";
}
if (vector_type == "double") {
type = "double";
Type = "Double";
array_type = "jdoubleArray";
}
std::string res_begin;
std::string res_end;
std::string fetch_object;
if (field_name.empty()) {
res_begin = "({ std::vector<" + vector_type + "> res_tmp_; ";
field_name = "res_tmp_";
res_end = " std::move(res_tmp_); })";
fetch_object = "p; ";
} else {
fetch_object = "jni::fetch_object(env, p, " + field_name + "fieldID); ";
}
std::string resize_vector;
if (!type.empty()) {
resize_vector = field_name + ".resize(length_tmp_); ";
} else {
resize_vector = field_name + ".reserve(length_tmp_); ";
if (!array_type.empty()) {
return "jni::fetch_vector(env, (" + array_type + ")" + fetch_object + ");";
}
std::string res;
if (!type.empty()) {
res =
"{ "
"j" +
type + "Array arr_tmp_ = (j" + type + "Array)" + fetch_object +
"if (arr_tmp_) { "
"jsize length_tmp_ = env->GetArrayLength(arr_tmp_); " +
resize_vector + "env->Get" + Type + "ArrayRegion(arr_tmp_, 0, length_tmp_, reinterpret_cast<j" + type +
" *>(&" + field_name +
"[0])); "
"env->DeleteLocalRef(arr_tmp_); "
"} }";
} else if (vector_type == string_type) {
res =
"{ "
"jobjectArray arr_tmp_ = (jobjectArray)" +
fetch_object +
"if (arr_tmp_) { "
"jsize length_tmp_ = env->GetArrayLength(arr_tmp_); " +
resize_vector +
"for (jsize i_tmp_ = 0; i_tmp_ < length_tmp_; i_tmp_++) { "
"jstring str_tmp_ = (jstring)env->GetObjectArrayElement(arr_tmp_, i_tmp_); " +
field_name +
".push_back(jni::from_jstring(env, str_tmp_)); "
"env->DeleteLocalRef(str_tmp_); "
"} "
"env->DeleteLocalRef(arr_tmp_); "
"} }";
std::string template_type;
if (vector_type == string_type) {
template_type = "std::string";
} else if (vector_type.compare(0, 11, "std::vector") == 0) {
const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(t->children[0]);
res =
"{ "
"jobjectArray arr_tmp_ = (jobjectArray)" +
fetch_object +
"if (arr_tmp_) { "
"jsize length_tmp_ = env->GetArrayLength(arr_tmp_); " +
resize_vector +
"for (jsize i_tmp_ = 0; i_tmp_ < length_tmp_; i_tmp_++) { "
"jobject p = env->GetObjectArrayElement(arr_tmp_, i_tmp_); " +
field_name + ".push_back(" + gen_vector_fetch("", child, vars, parser_type) +
"); "
"if (p) { env->DeleteLocalRef(p); "
"} } "
"env->DeleteLocalRef(arr_tmp_); "
"} }";
template_type = gen_type_name(child);
if (template_type.compare(0, 10, "object_ptr") == 0) {
template_type = gen_main_class_name(child->type);
}
template_type = "std::vector<" + template_type + ">";
} else if (vector_type == bytes_type) {
std::fprintf(stderr, "Vector of Bytes is not supported\n");
assert(false);
} else {
assert(vector_type.compare(0, 10, "object_ptr") == 0);
res =
"{ "
"jobjectArray arr_tmp_ = (jobjectArray)" +
fetch_object +
"if (arr_tmp_) { "
"jsize length_tmp_ = env->GetArrayLength(arr_tmp_); " +
resize_vector +
"for (jsize i_tmp_ = 0; i_tmp_ < length_tmp_; i_tmp_++) { "
"jobject o_ = env->GetObjectArrayElement(arr_tmp_, i_tmp_); " +
field_name + ".push_back(" + gen_main_class_name(t->type) +
"::fetch(env, o_)); "
"if (o_) { env->DeleteLocalRef(o_); "
"} } "
"env->DeleteLocalRef(arr_tmp_); "
"} }";
template_type = gen_main_class_name(t->type);
}
return res_begin + res + res_end;
return "jni::FetchVector<" + template_type + ">::fetch(env, (jobjectArray)" + fetch_object + ");";
}
std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name, const tl::tl_tree_type *tree_type,
@ -229,7 +160,7 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name,
}
if (name == "Bool") {
res = "env->GetBooleanField(p, " + field_name + "fieldID)";
res = "(env->GetBooleanField(p, " + field_name + "fieldID) != 0)";
} else if (name == "Int32") {
res = "env->GetIntField(p, " + field_name + "fieldID)";
} else if (name == "Int53" || name == "Int64") {
@ -242,13 +173,13 @@ std::string TD_TL_writer_jni_cpp::gen_type_fetch(const std::string &field_name,
res = "jni::from_bytes(env, (jbyteArray)jni::fetch_object(env, p, " + field_name + "fieldID))";
} else if (name == "Vector") {
const tl::tl_tree_type *child = static_cast<const tl::tl_tree_type *>(tree_type->children[0]);
return gen_vector_fetch(field_name, child, vars, parser_type);
res = gen_vector_fetch(field_name, child, vars, parser_type);
} else {
if (field_name == "") {
return gen_main_class_name(tree_type->type) + "::fetch(env, p)";
}
res = "({jobject jobject_tmp_ = jni::fetch_object(env, p, " + field_name + "fieldID); " +
gen_main_class_name(tree_type->type) + "::fetch(env, jobject_tmp_);})";
res = "jni::fetch_tl_object<" + gen_main_class_name(tree_type->type) + ">(env, jni::fetch_object(env, p, " +
field_name + "fieldID));";
}
return res_begin + res;
}
@ -523,7 +454,8 @@ std::string TD_TL_writer_jni_cpp::gen_store_function_begin(const std::string &st
"void " +
class_name + "::store(" + storer_name + " &s" +
std::string(storer_type <= 0 ? "" : ", const char *field_name") + ") const {\n" +
(storer_type <= 0 ? " if (!(s = env->AllocObject(Class))) { return; }\n"
(storer_type <= 0 ? " s = env->AllocObject(Class);\n"
" if (!s) { return; }\n"
: " if (!LOG_IS_STRIPPED(ERROR)) {\n"
" s.store_class_begin(field_name, \"" +
get_pretty_class_name(class_name) + "\");\n");

View File

@ -17,6 +17,7 @@
#include "td/utils/format.h"
#include "td/utils/logging.h"
#include "td/utils/Status.h"
#include "td/utils/StringBuilder.h"
#include "td/utils/tl_helpers.h"
#include <type_traits>
@ -245,8 +246,8 @@ void DeviceTokenManager::loop() {
net_query = G()->net_query_creator().create(
create_storer(telegram_api::account_unregisterDevice(token_type, info.token, std::move(other_user_ids))));
} else {
net_query = G()->net_query_creator().create(create_storer(
telegram_api::account_registerDevice(token_type, info.token, info.is_app_sandbox, std::move(other_user_ids))));
net_query = G()->net_query_creator().create(create_storer(telegram_api::account_registerDevice(
token_type, info.token, info.is_app_sandbox, std::move(other_user_ids))));
}
info.net_query_id = net_query->id();
G()->net_query_dispatcher().dispatch_with_callback(std::move(net_query), actor_shared(this, token_type));

View File

@ -32,7 +32,7 @@ jmethodID DoubleGetValueMethodID;
jclass get_jclass(JNIEnv *env, const char *class_name) {
jclass clazz = env->FindClass(class_name);
if (!clazz) {
LOG(INFO, "Can't find class [%s]", class_name);
LOG(INFO) << "Can't find class [" << class_name << "]";
env->ExceptionClear();
return clazz;
}
@ -41,7 +41,7 @@ jclass get_jclass(JNIEnv *env, const char *class_name) {
env->DeleteLocalRef(clazz);
if (!clazz_global) {
LOG(ERROR, "Can't create global reference to [%s]", class_name);
LOG(ERROR) << "Can't create global reference to [" << class_name << "]";
env->FatalError("Can't create global reference");
}
@ -55,7 +55,7 @@ jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name, const char
return res;
}
LOG(ERROR, "Can't find method %s %s", name, sig);
LOG(ERROR) << "Can't find method [" << name << "] with signature [" << sig << "]";
env->FatalError("Can't find method");
}
return nullptr;
@ -68,7 +68,7 @@ jfieldID get_field_id(JNIEnv *env, jclass clazz, const char *name, const char *s
return res;
}
LOG(ERROR, "Can't find field name=(%s) sig=(%s)", name, sig);
LOG(ERROR) << "Can't find field [" << name << "] with signature [" << sig << "]";
env->FatalError("Can't find field");
return 0;
}
@ -229,8 +229,10 @@ std::string from_bytes(JNIEnv *env, jbyteArray arr) {
std::string b;
if (arr != nullptr) {
jsize length = env->GetArrayLength(arr);
b.resize(narrow_cast<size_t>(length));
env->GetByteArrayRegion(arr, 0, length, reinterpret_cast<jbyte *>(&b[0]));
if (length != 0) {
b.resize(narrow_cast<size_t>(length));
env->GetByteArrayRegion(arr, 0, length, reinterpret_cast<jbyte *>(&b[0]));
}
env->DeleteLocalRef(arr);
}
return b;
@ -240,7 +242,7 @@ jbyteArray to_bytes(JNIEnv *env, const std::string &b) {
static_assert(sizeof(char) == sizeof(jbyte), "Mismatched jbyte size");
jsize length = narrow_cast<jsize>(b.size());
jbyteArray arr = env->NewByteArray(length);
if (arr != nullptr) {
if (arr != nullptr && length != 0) {
env->SetByteArrayRegion(arr, 0, length, reinterpret_cast<const jbyte *>(b.data()));
}
return arr;
@ -250,7 +252,7 @@ jintArray store_vector(JNIEnv *env, const std::vector<std::int32_t> &v) {
static_assert(sizeof(std::int32_t) == sizeof(jint), "Mismatched jint size");
jsize length = narrow_cast<jsize>(v.size());
jintArray arr = env->NewIntArray(length);
if (arr) {
if (arr != nullptr && length != 0) {
env->SetIntArrayRegion(arr, 0, length, reinterpret_cast<const jint *>(&v[0]));
}
return arr;
@ -260,7 +262,7 @@ jlongArray store_vector(JNIEnv *env, const std::vector<std::int64_t> &v) {
static_assert(sizeof(std::int64_t) == sizeof(jlong), "Mismatched jlong size");
jsize length = narrow_cast<jsize>(v.size());
jlongArray arr = env->NewLongArray(length);
if (arr) {
if (arr != nullptr && length != 0) {
env->SetLongArrayRegion(arr, 0, length, reinterpret_cast<const jlong *>(&v[0]));
}
return arr;
@ -270,7 +272,7 @@ jdoubleArray store_vector(JNIEnv *env, const std::vector<double> &v) {
static_assert(sizeof(double) == sizeof(jdouble), "Mismatched jdouble size");
jsize length = narrow_cast<jsize>(v.size());
jdoubleArray arr = env->NewDoubleArray(length);
if (arr) {
if (arr != nullptr && length != 0) {
env->SetDoubleArrayRegion(arr, 0, length, reinterpret_cast<const jdouble *>(&v[0]));
}
return arr;
@ -279,7 +281,7 @@ jdoubleArray store_vector(JNIEnv *env, const std::vector<double> &v) {
jobjectArray store_vector(JNIEnv *env, const std::vector<std::string> &v) {
jsize length = narrow_cast<jsize>(v.size());
jobjectArray arr = env->NewObjectArray(length, StringClass, 0);
if (arr) {
if (arr != nullptr) {
for (jsize i = 0; i < length; i++) {
jstring str = to_jstring(env, v[i]);
if (str) {
@ -291,5 +293,44 @@ jobjectArray store_vector(JNIEnv *env, const std::vector<std::string> &v) {
return arr;
}
std::vector<std::int32_t> fetch_vector(JNIEnv *env, jintArray arr) {
std::vector<std::int32_t> result;
if (arr != nullptr) {
jsize length = env->GetArrayLength(arr);
if (length != 0) {
result.resize(length);
env->GetIntArrayRegion(arr, 0, length, reinterpret_cast<jint *>(&result[0]));
}
env->DeleteLocalRef(arr);
}
return result;
}
std::vector<std::int64_t> fetch_vector(JNIEnv *env, jlongArray arr) {
std::vector<std::int64_t> result;
if (arr != nullptr) {
jsize length = env->GetArrayLength(arr);
if (length != 0) {
result.resize(length);
env->GetLongArrayRegion(arr, 0, length, reinterpret_cast<jlong *>(&result[0]));
}
env->DeleteLocalRef(arr);
}
return result;
}
std::vector<double> fetch_vector(JNIEnv *env, jdoubleArray arr) {
std::vector<double> result;
if (arr != nullptr) {
jsize length = env->GetArrayLength(arr);
if (length != 0) {
result.resize(length);
env->GetDoubleArrayRegion(arr, 0, length, reinterpret_cast<jdouble *>(&result[0]));
}
env->DeleteLocalRef(arr);
}
return result;
}
} // namespace jni
} // namespace td

View File

@ -74,7 +74,7 @@ template <class T>
jobjectArray store_vector(JNIEnv *env, const std::vector<T> &v) {
jint length = static_cast<jint>(v.size());
jobjectArray arr = env->NewObjectArray(length, T::element_type::Class, jobject());
if (arr) {
if (arr != nullptr) {
for (jint i = 0; i < length; i++) {
if (v[i] != nullptr) {
jobject stored_object;
@ -114,7 +114,7 @@ template <class T>
jobjectArray store_vector(JNIEnv *env, const std::vector<std::vector<T>> &v) {
jint length = static_cast<jint>(v.size());
jobjectArray arr = env->NewObjectArray(length, get_array_class<typename T::element_type>::get(), 0);
if (arr) {
if (arr != nullptr) {
for (jint i = 0; i < length; i++) {
auto stored_array = store_vector(env, v[i]);
if (stored_array) {
@ -126,5 +126,73 @@ jobjectArray store_vector(JNIEnv *env, const std::vector<std::vector<T>> &v) {
return arr;
}
template <class T>
auto fetch_tl_object(JNIEnv *env, jobject obj) {
decltype(T::fetch(env, obj)) result;
if (obj != nullptr) {
result = T::fetch(env, obj);
env->DeleteLocalRef(obj);
}
return result;
}
std::vector<std::int32_t> fetch_vector(JNIEnv *env, jintArray arr);
std::vector<std::int64_t> fetch_vector(JNIEnv *env, jlongArray arr);
std::vector<double> fetch_vector(JNIEnv *env, jdoubleArray arr);
template <class T>
struct FetchVector {
static auto fetch(JNIEnv *env, jobjectArray arr) {
std::vector<decltype(fetch_tl_object<T>(env, jobject()))> result;
if (arr != nullptr) {
jsize length = env->GetArrayLength(arr);
result.reserve(length);
for (jsize i = 0; i < length; i++) {
result.push_back(fetch_tl_object<T>(env, env->GetObjectArrayElement(arr, i)));
}
env->DeleteLocalRef(arr);
}
return result;
}
};
template <>
struct FetchVector<std::string> {
static std::vector<std::string> fetch(JNIEnv *env, jobjectArray arr) {
std::vector<std::string> result;
if (arr != nullptr) {
jsize length = env->GetArrayLength(arr);
result.reserve(length);
for (jsize i = 0; i < length; i++) {
jstring str = (jstring)env->GetObjectArrayElement(arr, i);
result.push_back(jni::from_jstring(env, str));
if (str) {
env->DeleteLocalRef(str);
}
}
env->DeleteLocalRef(arr);
}
return result;
}
};
template <class T>
struct FetchVector<std::vector<T>> {
static auto fetch(JNIEnv *env, jobjectArray arr) {
std::vector<decltype(FetchVector<T>::fetch(env, jobjectArray()))> result;
if (arr != nullptr) {
jsize length = env->GetArrayLength(arr);
result.reserve(length);
for (jsize i = 0; i < length; i++) {
result.push_back(FetchVector<T>::fetch(env, (jobjectArray)env->GetObjectArrayElement(arr, i)));
}
env->DeleteLocalRef(arr);
}
return result;
}
};
} // namespace jni
} // namespace td

View File

@ -165,10 +165,6 @@ class DowncastHelper : public T {
int32 get_id() const override {
return constructor_;
}
void store(TlStorerUnsafe &s) const override {
}
void store(TlStorerCalcLength &s) const override {
}
void store(TlStorerToString &s, const char *field_name) const override {
}