Browse Source

Merge pull request #102862 from dsnopek/java-class-wrapper-get-exception

JavaClassWrapper: Allow handling exceptions (rather than just crashing)
Rémi Verschelde 5 months ago
parent
commit
11d8e2e811

+ 8 - 0
doc/classes/JavaClassWrapper.xml

@@ -15,10 +15,18 @@
 
 		print(datetime.format(formatter))
 		[/codeblock]
+		[b]Warning:[/b] When calling Java methods, be sure to check [method JavaClassWrapper.get_exception] to check if the method threw an exception.
 	</description>
 	<tutorials>
 	</tutorials>
 	<methods>
+		<method name="get_exception">
+			<return type="JavaObject" />
+			<description>
+				Returns the Java exception from the last call into a Java class. If there was no exception, it will return [code]null[/code].
+				[b]Note:[/b] This method only works on Android. On every other platform, this method will always return [code]null[/code].
+			</description>
+		</method>
 		<method name="wrap">
 			<return type="JavaClass" />
 			<param index="0" name="name" type="String" />

+ 1 - 0
platform/android/api/api.cpp

@@ -70,6 +70,7 @@ void JavaObject::_bind_methods() {
 
 void JavaClassWrapper::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("wrap", "name"), &JavaClassWrapper::wrap);
+	ClassDB::bind_method(D_METHOD("get_exception"), &JavaClassWrapper::get_exception);
 }
 
 #if !defined(ANDROID_ENABLED)

+ 6 - 0
platform/android/api/java_class_wrapper.h

@@ -271,6 +271,8 @@ class JavaClassWrapper : public Object {
 	bool _get_type_sig(JNIEnv *env, jobject obj, uint32_t &sig, String &strsig);
 #endif
 
+	Ref<JavaObject> exception;
+
 	Ref<JavaClass> _wrap(const String &p_class, bool p_allow_private_methods_access);
 
 	static JavaClassWrapper *singleton;
@@ -285,6 +287,10 @@ public:
 		return _wrap(p_class, false);
 	}
 
+	Ref<JavaObject> get_exception() {
+		return exception;
+	}
+
 #ifdef ANDROID_ENABLED
 	Ref<JavaClass> wrap_jclass(jclass p_class, bool p_allow_private_methods_access = false);
 #endif

+ 14 - 0
platform/android/java_class_wrapper.cpp

@@ -517,6 +517,20 @@ bool JavaClass::_call_method(JavaObject *p_instance, const StringName &p_method,
 		env->DeleteLocalRef(E);
 	}
 
+	jobject exception = env->ExceptionOccurred();
+	if (exception) {
+		env->ExceptionClear();
+
+		jclass java_class = env->GetObjectClass(exception);
+		Ref<JavaClass> java_class_wrapped = JavaClassWrapper::singleton->wrap_jclass(java_class);
+		env->DeleteLocalRef(java_class);
+
+		JavaClassWrapper::singleton->exception.instantiate(java_class_wrapped, exception);
+		env->DeleteLocalRef(exception);
+	} else {
+		JavaClassWrapper::singleton->exception.unref();
+	}
+
 	return success;
 }