lib: throw C++ exceptions on exceptions from Java calls

This commit is contained in:
Oscar Mira 2023-02-26 13:23:54 +01:00
parent 56ecb91657
commit a34ace5fc8
6 changed files with 47 additions and 35 deletions

View File

@ -29,7 +29,6 @@ class ScopedFd {
if (!parcel_file_descriptor.is_null()) {
m_fd = parcel_file_descriptor.callIntMethod(env,
ParcelFileDescriptor_detachFd);
LOG_FATAL_IF(checkException(env));
}
}

View File

@ -35,11 +35,8 @@ bool RemoteNodeClient::is_connected(bool* ssl) {
RemoteNodeClient::HttpResponse jvmToHttpResponse(JNIEnv* env, JvmRef<jobject>& j_http_response) {
jint code = j_http_response.callIntMethod(env, HttpResponse_getCode);
LOG_FATAL_IF(checkException(env));
jstring mime_type = j_http_response.callStringMethod(env, HttpResponse_getContentType);
LOG_FATAL_IF(checkException(env));
jobject body = j_http_response.callObjectMethod(env, HttpResponse_getBody);
LOG_FATAL_IF(checkException(env));
return {
code,
(mime_type != nullptr) ? jvmToStdString(env, mime_type) : "",
@ -58,33 +55,34 @@ bool RemoteNodeClient::invoke(const boost::string_ref uri,
for (const auto& p: additional_params) {
header << p.first << ": " << p.second << "\r\n";
}
ScopedJvmLocalRef<jobject> j_response = {
env, m_remote_node_client.callObjectMethod(
env, IRemoteNodeClient_makeRequest,
nativeToJvmString(env, method.data()).obj(),
nativeToJvmString(env, uri.data()).obj(),
nativeToJvmString(env, header.str()).obj(),
nativeToJvmByteArray(env, body.data(), body.length()).obj()
)
};
if (checkException(env)) {
try {
ScopedJvmLocalRef<jobject> j_response = {
env, m_remote_node_client.callObjectMethod(
env, IRemoteNodeClient_makeRequest,
nativeToJvmString(env, method.data()).obj(),
nativeToJvmString(env, uri.data()).obj(),
nativeToJvmString(env, header.str()).obj(),
nativeToJvmByteArray(env, body.data(), body.length()).obj()
)
};
m_response_info.clear();
if (j_response.is_null()) {
return false;
}
HttpResponse http_response = jvmToHttpResponse(env, j_response);
if (http_response.code == 401) {
// Handle HTTP unauthorized in the same way as http_simple_client_template.
return false;
}
m_response_info.m_response_code = http_response.code;
m_response_info.m_mime_tipe = http_response.content_type;
if (http_response.body.is_valid()) {
http_response.body.read(&m_response_info.m_body);
}
} catch (std::runtime_error& e) {
LOGE("Unhandled exception in RemoteNodeClient");
return false;
}
m_response_info.clear();
if (j_response.is_null()) {
return false;
}
HttpResponse http_response = jvmToHttpResponse(env, j_response);
if (http_response.code == 401) {
// Handle unauthorized in the same way as http_simple_client_template.
return false;
}
m_response_info.m_response_code = http_response.code;
m_response_info.m_mime_tipe = http_response.content_type;
if (http_response.body.is_valid()) {
http_response.body.read(&m_response_info.m_body);
}
if (ppresponse_info) {
*ppresponse_info = std::addressof(m_response_info);
}

View File

@ -104,34 +104,43 @@ void JvmRef<jobject>::callVoidMethod(JNIEnv* env,
va_list args;
va_start(args, method_id);
env->CallVoidMethodV(obj(), method_id, args);
throwRuntimeErrorOnException(env);
}
jint JvmRef<jobject>::callIntMethod(JNIEnv* env,
jmethodID method_id, ...) const {
va_list args;
va_start(args, method_id);
return env->CallIntMethodV(obj(), method_id, args);
jint ret = env->CallIntMethodV(obj(), method_id, args);
throwRuntimeErrorOnException(env);
return ret;
}
jboolean JvmRef<jobject>::callBooleanMethod(JNIEnv* env,
jmethodID method_id, ...) const {
va_list args;
va_start(args, method_id);
return env->CallBooleanMethodV(obj(), method_id, args);
jboolean ret = env->CallBooleanMethodV(obj(), method_id, args);
throwRuntimeErrorOnException(env);
return ret;
}
jobject JvmRef<jobject>::callObjectMethod(JNIEnv* env,
jmethodID method_id, ...) const {
va_list args;
va_start(args, method_id);
return env->CallObjectMethodV(obj(), method_id, args);
jobject ret = env->CallObjectMethodV(obj(), method_id, args);
throwRuntimeErrorOnException(env);
return ret;
}
jstring JvmRef<jobject>::callStringMethod(JNIEnv* env,
jmethodID method_id, ...) const {
va_list args;
va_start(args, method_id);
return (jstring) env->CallObjectMethodV(obj(), method_id, args);
auto ret = (jstring) env->CallObjectMethodV(obj(), method_id, args);
throwRuntimeErrorOnException(env);
return ret;
}
jmethodID JvmRef<jobject>::getMethodId(JNIEnv* env,

View File

@ -3,6 +3,7 @@
#include <jni.h>
#include <stdexcept>
#include <string>
#include <vector>
@ -18,14 +19,21 @@ JNIEnv* getJniEnv();
JNIEnv* initializeJvm(JavaVM* jvm, int version);
// Checks for any Java exception and clears currently thrown exception.
static bool inline checkException(JNIEnv* env) {
static bool inline checkException(JNIEnv* env, bool log_exception = true) {
if (env->ExceptionCheck()) {
if (log_exception) env->ExceptionDescribe();
env->ExceptionClear();
return true;
}
return false;
}
static void inline throwRuntimeErrorOnException(JNIEnv* env) {
if (checkException(env, false)) {
throw std::runtime_error("Uncaught exception returned from Java call");
}
}
// --------------------------------------------------------------------------
// Originally these classes are from WebRTC and Chromium.
// --------------------------------------------------------------------------

View File

@ -74,7 +74,6 @@ void JvmLogSink::write(const std::string& tag,
ScopedJvmLocalRef<jstring> j_msg = nativeToJvmString(env, msg);
m_logger.callVoidMethod(env, Logger_logFromNative,
pri_idx, j_tag.obj(), j_msg.obj());
LOG_FATAL_IF(checkException(env));
}
void JvmLogSink::set_logger(JNIEnv* env, const JvmRef<jobject>& logger) {

View File

@ -132,7 +132,6 @@ void Wallet::handleBalanceChanged(uint64_t at_block_height) {
m_blockchain_height = at_block_height;
JNIEnv* env = getJniEnv();
m_callback.callVoidMethod(env, Wallet_onRefresh, at_block_height, true);
LOG_FATAL_IF(checkException(env));
}
void Wallet::handleNewBlock(uint64_t height) {