diff --git a/jni/example/android/app/build.gradle b/jni/example/android/app/build.gradle index 3c6742ce..fbcc3561 100644 --- a/jni/example/android/app/build.gradle +++ b/jni/example/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') diff --git a/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java b/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java index ff9c0766..3caf02af 100644 --- a/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java +++ b/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java @@ -73,10 +73,19 @@ public static Object newInstance(String binaryName, long port, long isolateId, l return obj; } + private static final class DartException extends Exception { + private DartException(String message) { + super(message); + } + } + @Override - public Object invoke(Object proxy, Method method, Object[] args) { + public Object invoke(Object proxy, Method method, Object[] args) throws DartException { Object[] result = _invoke(port, isolateId, functionPtr, proxy, getDescriptor(method), args); _cleanUp((Long) result[0]); + if (result[1] instanceof DartException) { + throw (DartException) result[1]; + } return result[1]; } diff --git a/jni/lib/src/jni.dart b/jni/lib/src/jni.dart index 2957105a..d5495bc7 100644 --- a/jni/lib/src/jni.dart +++ b/jni/lib/src/jni.dart @@ -299,6 +299,13 @@ extension ProtectedJniExtensions on Jni { return lookup; } + /// Returns a new DartException. + static JObjectPtr newDartException(String message) { + return Jni._bindings + .DartException__ctor(Jni.env.toJStringPtr(message)) + .object; + } + /// Returns a new PortContinuation. static JObjectPtr newPortContinuation(ReceivePort port) { return Jni._bindings @@ -323,7 +330,7 @@ extension ProtectedJniExtensions on Jni { .object; } - /// Return the result of a callback.. + /// Returns the result of a callback.. static void returnResult( Pointer result, JObjectPtr object) async { Jni._bindings.resultFor(result, object); @@ -334,28 +341,30 @@ extension AdditionalEnvMethods on GlobalJniEnv { /// Convenience method for converting a [JStringPtr] /// to dart string. /// if [deleteOriginal] is specified, jstring passed will be deleted using - /// DeleteLocalRef. + /// DeleteGlobalRef. String toDartString(JStringPtr jstringPtr, {bool deleteOriginal = false}) { if (jstringPtr == nullptr) { throw const JNullException(); } - final chars = GetStringUTFChars(jstringPtr, nullptr); + final chars = GetStringChars(jstringPtr, nullptr); if (chars == nullptr) { throw InvalidJStringException(jstringPtr); } - final result = chars.cast().toDartString(); - ReleaseStringUTFChars(jstringPtr, chars); + final result = chars.cast().toDartString(); + ReleaseStringChars(jstringPtr, chars); if (deleteOriginal) { DeleteGlobalRef(jstringPtr); } return result; } - /// Return a new [JStringPtr] from contents of [s]. + /// Returns a new [JStringPtr] from contents of [s]. JStringPtr toJStringPtr(String s) => using((arena) { - final utf = s.toNativeUtf8().cast(); - final result = NewStringUTF(utf); - malloc.free(utf); + final utf = s.toNativeUtf16(allocator: arena).cast(); + final result = NewString(utf, s.length); + if (utf == nullptr) { + throw 'Fatal: cannot convert string to Java string: $s'; + } return result; }); diff --git a/jni/lib/src/lang/jstring.dart b/jni/lib/src/lang/jstring.dart index 5bfcce5c..f1df76c4 100644 --- a/jni/lib/src/lang/jstring.dart +++ b/jni/lib/src/lang/jstring.dart @@ -47,20 +47,11 @@ class JString extends JObject { /// Construct a new [JString] with [reference] as its underlying reference. JString.fromRef(JStringPtr reference) : super.fromRef(reference); - static JStringPtr _toJavaString(String s) => using((arena) { - final chars = s.toNativeUtf16(allocator: arena).cast(); - final jstr = Jni.env.NewString(chars, s.length); - if (jstr == nullptr) { - throw 'Fatal: cannot convert string to Java string: $s'; - } - return jstr; - }); - /// The number of Unicode characters in this Java string. int get length => Jni.env.GetStringLength(reference); /// Construct a [JString] from the contents of Dart string [s]. - JString.fromString(String s) : super.fromRef(_toJavaString(s)); + JString.fromString(String s) : super.fromRef(Jni.env.toJStringPtr(s)); /// Returns the contents as a Dart String. /// diff --git a/jni/lib/src/third_party/jni_bindings_generated.dart b/jni/lib/src/third_party/jni_bindings_generated.dart index bdd6ab74..892f69e5 100644 --- a/jni/lib/src/third_party/jni_bindings_generated.dart +++ b/jni/lib/src/third_party/jni_bindings_generated.dart @@ -178,22 +178,19 @@ class JniBindings { late final _InitDartApiDL = _InitDartApiDLPtr.asFunction)>(); - void resultFor( - ffi.Pointer result, - JObjectPtr object, + JniResult DartException__ctor( + JStringPtr message, ) { - return _resultFor( - result, - object, + return _DartException__ctor( + message, ); } - late final _resultForPtr = _lookup< - ffi.NativeFunction< - ffi.Void Function( - ffi.Pointer, JObjectPtr)>>('resultFor'); - late final _resultFor = _resultForPtr - .asFunction, JObjectPtr)>(); + late final _DartException__ctorPtr = + _lookup>( + 'DartException__ctor'); + late final _DartException__ctor = + _DartException__ctorPtr.asFunction(); JniResult PortContinuation__ctor( int j, @@ -228,6 +225,23 @@ class JniBindings { late final _PortProxy__newInstance = _PortProxy__newInstancePtr.asFunction< JniResult Function(JObjectPtr, int, int)>(); + void resultFor( + ffi.Pointer result, + JObjectPtr object, + ) { + return _resultFor( + result, + object, + ); + } + + late final _resultForPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer, JObjectPtr)>>('resultFor'); + late final _resultFor = _resultForPtr + .asFunction, JObjectPtr)>(); + ffi.Pointer GetGlobalEnv() { return _GetGlobalEnv(); } diff --git a/jni/src/dartjni.c b/jni/src/dartjni.c index dc595a9c..7c5951bc 100644 --- a/jni/src/dartjni.c +++ b/jni/src/dartjni.c @@ -569,6 +569,29 @@ FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data) { return Dart_InitializeApiDL(data); } +// com.github.dart_lang.jni.DartException +jclass _c_DartException = NULL; + +jmethodID _m_DartException__ctor = NULL; +FFI_PLUGIN_EXPORT JniResult DartException__ctor(jstring message) { + attach_thread(); + load_class_global_ref(&_c_DartException, + "com/github/dart_lang/jni/PortProxy$DartException"); + if (_c_DartException == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_DartException, &_m_DartException__ctor, "", + "(Ljava/lang/String;)V"); + if (_m_DartException__ctor == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_DartException, + _m_DartException__ctor, message); + jthrowable exception = check_exception(); + if (exception == NULL) { + _result = to_global_ref(_result); + } + return (JniResult){.value = {.l = _result}, .exception = check_exception()}; +} + JNIEXPORT void JNICALL Java_com_github_dart_1lang_jni_PortContinuation__1resumeWith(JNIEnv* env, jclass clazz, diff --git a/jni/src/dartjni.h b/jni/src/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jni/src/dartjni.h +++ b/jni/src/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/android_test_runner/android/app/build.gradle b/jnigen/android_test_runner/android/app/build.gradle index e0c777fb..58cd27a4 100644 --- a/jnigen/android_test_runner/android/app/build.gradle +++ b/jnigen/android_test_runner/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') diff --git a/jnigen/example/in_app_java/android/app/build.gradle b/jnigen/example/in_app_java/android/app/build.gradle index 8f38e430..59ebf169 100644 --- a/jnigen/example/in_app_java/android/app/build.gradle +++ b/jnigen/example/in_app_java/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') diff --git a/jnigen/example/in_app_java/src/android_utils/dartjni.h b/jnigen/example/in_app_java/src/android_utils/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jnigen/example/in_app_java/src/android_utils/dartjni.h +++ b/jnigen/example/in_app_java/src/android_utils/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/example/kotlin_plugin/example/android/app/build.gradle b/jnigen/example/kotlin_plugin/example/android/app/build.gradle index f371e650..7f1cb3e6 100644 --- a/jnigen/example/kotlin_plugin/example/android/app/build.gradle +++ b/jnigen/example/kotlin_plugin/example/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') diff --git a/jnigen/example/kotlin_plugin/src/dartjni.h b/jnigen/example/kotlin_plugin/src/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jnigen/example/kotlin_plugin/src/dartjni.h +++ b/jnigen/example/kotlin_plugin/src/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/example/notification_plugin/example/android/app/build.gradle b/jnigen/example/notification_plugin/example/android/app/build.gradle index ee3c62fa..7f66900c 100644 --- a/jnigen/example/notification_plugin/example/android/app/build.gradle +++ b/jnigen/example/notification_plugin/example/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') diff --git a/jnigen/example/notification_plugin/src/dartjni.h b/jnigen/example/notification_plugin/src/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jnigen/example/notification_plugin/src/dartjni.h +++ b/jnigen/example/notification_plugin/src/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/example/pdfbox_plugin/example/android/app/build.gradle b/jnigen/example/pdfbox_plugin/example/android/app/build.gradle index 162ad5b0..c5791ba9 100644 --- a/jnigen/example/pdfbox_plugin/example/android/app/build.gradle +++ b/jnigen/example/pdfbox_plugin/example/android/app/build.gradle @@ -8,7 +8,7 @@ if (localPropertiesFile.exists()) { def flutterRoot = localProperties.getProperty('flutter.sdk') if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") + throw new FileNotFoundException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") } def flutterVersionCode = localProperties.getProperty('flutter.versionCode') diff --git a/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h b/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h +++ b/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/lib/src/bindings/dart_generator.dart b/jnigen/lib/src/bindings/dart_generator.dart index 3bc72cc6..d21665c7 100644 --- a/jnigen/lib/src/bindings/dart_generator.dart +++ b/jnigen/lib/src/bindings/dart_generator.dart @@ -439,14 +439,18 @@ class $name$typeParamsDef extends $superName { int $p, $MethodInvocation $i, ) { - final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); - final $a = $i.args; + try { + final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); + final $a = $i.args; '''); final proxyMethodIf = _InterfaceMethodIf(resolver, s); for (final method in node.methods) { method.accept(proxyMethodIf); } s.write(''' + } catch (e) { + return $_protectedExtension.newDartException(e.toString()); + } return jni.nullptr; } @@ -469,19 +473,17 @@ class $name$typeParamsDef extends $superName { ).._\$p = \$p; final \$a = \$p.sendPort.nativePort; _\$impls[\$a] = \$impl; -'''); - s.write(r''' - $p.listen(($m) { - if ($m == null) { - _$impls.remove($p.sendPort.nativePort); - $p.close(); + \$p.listen((\$m) { + if (\$m == null) { + _\$impls.remove(\$p.sendPort.nativePort); + \$p.close(); return; } - final $i = $MethodInvocation.fromMessage($m); - final $r = _$invokeMethod($p.sendPort.nativePort, $i); - ProtectedJniExtensions.returnResult($i.result, $r); + final \$i = \$MethodInvocation.fromMessage(\$m); + final \$r = _\$invokeMethod(\$p.sendPort.nativePort, \$i); + $_protectedExtension.returnResult(\$i.result, \$r); }); - return $x; + return \$x; } '''); } @@ -1645,17 +1647,17 @@ class _InterfaceMethodIf extends Visitor { final saveResult = isVoid ? '' : 'final \$r = '; final name = node.finalName; s.write(''' - if (\$d == r"$signature") { - ${saveResult}_\$impls[\$p]!.$name( + if (\$d == r"$signature") { + ${saveResult}_\$impls[\$p]!.$name( '''); for (var i = 0; i < node.params.length; ++i) { node.params[i].accept(_InterfaceParamCast(resolver, s, paramIndex: i)); } const returnBox = _InterfaceReturnBox(); s.write(''' - ); - return ${node.returnType.accept(returnBox)}; - } + ); + return ${node.returnType.accept(returnBox)}; + } '''); } } diff --git a/jnigen/lib/src/config/experiments.dart b/jnigen/lib/src/config/experiments.dart index d0eb39dd..6bb65c10 100644 --- a/jnigen/lib/src/config/experiments.dart +++ b/jnigen/lib/src/config/experiments.dart @@ -31,7 +31,7 @@ class Experiment { } final result = search.single; if (result.isExpired) { - throw 'The experiment $s can no longer be used in this version. '; + throw 'The experiment $s can no longer be used in this version.'; } return result; } diff --git a/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h b/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h +++ b/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h b/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h +++ b/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/test/regenerate_examples_test.dart b/jnigen/test/regenerate_examples_test.dart index 5afeebea..35ab2e05 100644 --- a/jnigen/test/regenerate_examples_test.dart +++ b/jnigen/test/regenerate_examples_test.dart @@ -29,7 +29,7 @@ void testExample(String exampleName, String dartOutput, String? cOutput, {bool isLargeTest = false}) { test( 'Generate and compare bindings for $exampleName', - timeout: const Timeout.factor(2), + timeout: const Timeout.factor(3), () async { final examplePath = join('example', exampleName); final configPath = join(examplePath, 'jnigen.yaml'); diff --git a/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h b/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h index 0a7f6691..8f1dc748 100644 --- a/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h +++ b/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h @@ -410,7 +410,8 @@ static inline JniResult to_global_ref_result(jobject ref) { FFI_PLUGIN_EXPORT intptr_t InitDartApiDL(void* data); -FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); +FFI_PLUGIN_EXPORT +JniResult DartException__ctor(jstring message); FFI_PLUGIN_EXPORT JniResult PortContinuation__ctor(int64_t j); @@ -419,3 +420,5 @@ FFI_PLUGIN_EXPORT JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object); diff --git a/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c b/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c index 62b150ed..20c7e7e5 100644 --- a/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c +++ b/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c @@ -2786,6 +2786,111 @@ JniResult MyInterfaceConsumer__consumeOnSameThread(jobject myInterface, return (JniResult){.value = {.j = 0}, .exception = check_exception()}; } +// com.github.dart_lang.jnigen.interfaces.MyRunnable +jclass _c_MyRunnable = NULL; + +jmethodID _m_MyRunnable__run = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnable__run(jobject self_) { + load_env(); + load_class_global_ref(&_c_MyRunnable, + "com/github/dart_lang/jnigen/interfaces/MyRunnable"); + if (_c_MyRunnable == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnable, &_m_MyRunnable__run, "run", "()V"); + if (_m_MyRunnable__run == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, _m_MyRunnable__run); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +// com.github.dart_lang.jnigen.interfaces.MyRunnableRunner +jclass _c_MyRunnableRunner = NULL; + +jmethodID _m_MyRunnableRunner__new0 = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnableRunner__new0(jobject runnable) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnableRunner, &_m_MyRunnableRunner__new0, "", + "(Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;)V"); + if (_m_MyRunnableRunner__new0 == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + jobject _result = (*jniEnv)->NewObject(jniEnv, _c_MyRunnableRunner, + _m_MyRunnableRunner__new0, runnable); + return to_global_ref_result(_result); +} + +jmethodID _m_MyRunnableRunner__runOnSameThread = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnableRunner__runOnSameThread(jobject self_) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnableRunner, &_m_MyRunnableRunner__runOnSameThread, + "runOnSameThread", "()V"); + if (_m_MyRunnableRunner__runOnSameThread == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_MyRunnableRunner__runOnSameThread); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jmethodID _m_MyRunnableRunner__runOnAnotherThread = NULL; +FFI_PLUGIN_EXPORT +JniResult MyRunnableRunner__runOnAnotherThread(jobject self_) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_method(_c_MyRunnableRunner, &_m_MyRunnableRunner__runOnAnotherThread, + "runOnAnotherThread", "()V"); + if (_m_MyRunnableRunner__runOnAnotherThread == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + (*jniEnv)->CallVoidMethod(jniEnv, self_, + _m_MyRunnableRunner__runOnAnotherThread); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + +jfieldID _f_MyRunnableRunner__error = NULL; +FFI_PLUGIN_EXPORT +JniResult get_MyRunnableRunner__error(jobject self_) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyRunnableRunner, &_f_MyRunnableRunner__error, "error", + "Ljava/lang/Throwable;"); + jobject _result = + (*jniEnv)->GetObjectField(jniEnv, self_, _f_MyRunnableRunner__error); + return to_global_ref_result(_result); +} + +FFI_PLUGIN_EXPORT +JniResult set_MyRunnableRunner__error(jobject self_, jobject value) { + load_env(); + load_class_global_ref( + &_c_MyRunnableRunner, + "com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + if (_c_MyRunnableRunner == NULL) + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; + load_field(_c_MyRunnableRunner, &_f_MyRunnableRunner__error, "error", + "Ljava/lang/Throwable;"); + (*jniEnv)->SetObjectField(jniEnv, self_, _f_MyRunnableRunner__error, value); + return (JniResult){.value = {.j = 0}, .exception = check_exception()}; +} + // com.github.dart_lang.jnigen.annotations.JsonSerializable$Case jclass _c_JsonSerializable_Case = NULL; diff --git a/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart b/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart index cd47f44c..5154b759 100644 --- a/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart +++ b/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart @@ -3371,42 +3371,46 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { int $p, $MethodInvocation $i, ) { - final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); - final $a = $i.args; - if ($d == r"voidCallback(Ljava/lang/String;)V") { - _$impls[$p]!.voidCallback( - $a[0].castTo(const jni.JStringType(), deleteOriginal: true), - ); - return jni.nullptr; - } - if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { - final $r = _$impls[$p]!.stringCallback( - $a[0].castTo(const jni.JStringType(), deleteOriginal: true), - ); - return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); - } - if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { - final $r = _$impls[$p]!.varCallback( - $a[0].castTo(_$impls[$p]!.T, deleteOriginal: true), - ); - return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); - } - if ($d == r"manyPrimitives(IZCD)J") { - final $r = _$impls[$p]!.manyPrimitives( - $a[0] - .castTo(const jni.JIntegerType(), deleteOriginal: true) - .intValue(deleteOriginal: true), - $a[1] - .castTo(const jni.JBooleanType(), deleteOriginal: true) - .booleanValue(deleteOriginal: true), - $a[2] - .castTo(const jni.JCharacterType(), deleteOriginal: true) - .charValue(deleteOriginal: true), - $a[3] - .castTo(const jni.JDoubleType(), deleteOriginal: true) - .doubleValue(deleteOriginal: true), - ); - return jni.JLong($r).toPointer(); + try { + final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); + final $a = $i.args; + if ($d == r"voidCallback(Ljava/lang/String;)V") { + _$impls[$p]!.voidCallback( + $a[0].castTo(const jni.JStringType(), deleteOriginal: true), + ); + return jni.nullptr; + } + if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { + final $r = _$impls[$p]!.stringCallback( + $a[0].castTo(const jni.JStringType(), deleteOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { + final $r = _$impls[$p]!.varCallback( + $a[0].castTo(_$impls[$p]!.T, deleteOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"manyPrimitives(IZCD)J") { + final $r = _$impls[$p]!.manyPrimitives( + $a[0] + .castTo(const jni.JIntegerType(), deleteOriginal: true) + .intValue(deleteOriginal: true), + $a[1] + .castTo(const jni.JBooleanType(), deleteOriginal: true) + .booleanValue(deleteOriginal: true), + $a[2] + .castTo(const jni.JCharacterType(), deleteOriginal: true) + .charValue(deleteOriginal: true), + $a[3] + .castTo(const jni.JDoubleType(), deleteOriginal: true) + .doubleValue(deleteOriginal: true), + ); + return jni.JLong($r).toPointer(); + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); } return jni.nullptr; } @@ -3646,6 +3650,243 @@ class $MyInterfaceConsumerType extends jni.JObjType { } } +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnable +class MyRunnable extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnable.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableType(); + static final _run = jniLookup< + ffi + .NativeFunction)>>( + "MyRunnable__run") + .asFunction)>(); + + /// from: public abstract void run() + void run() { + return _run(reference).check(); + } + + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; + ReceivePort? _$p; + + static jni.JObjectPtr _$invoke( + int port, + jni.JObjectPtr descriptor, + jni.JObjectPtr args, + ) { + return _$invokeMethod( + port, + $MethodInvocation.fromAddresses( + 0, + descriptor.address, + args.address, + ), + ); + } + + static final ffi.Pointer< + ffi.NativeFunction< + jni.JObjectPtr Function( + ffi.Uint64, jni.JObjectPtr, jni.JObjectPtr)>> + _$invokePointer = ffi.Pointer.fromFunction(_$invoke); + + static ffi.Pointer _$invokeMethod( + int $p, + $MethodInvocation $i, + ) { + try { + final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); + final $a = $i.args; + if ($d == r"run()V") { + _$impls[$p]!.run(); + return jni.nullptr; + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); + } + return jni.nullptr; + } + + factory MyRunnable.implement( + $MyRunnableImpl $impl, + ) { + final $p = ReceivePort(); + final $x = MyRunnable.fromRef( + ProtectedJniExtensions.newPortProxy( + r"com.github.dart_lang.jnigen.interfaces.MyRunnable", + $p, + _$invokePointer, + ), + ).._$p = $p; + final $a = $p.sendPort.nativePort; + _$impls[$a] = $impl; + $p.listen(($m) { + if ($m == null) { + _$impls.remove($p.sendPort.nativePort); + $p.close(); + return; + } + final $i = $MethodInvocation.fromMessage($m); + final $r = _$invokeMethod($p.sendPort.nativePort, $i); + ProtectedJniExtensions.returnResult($i.result, $r); + }); + return $x; + } +} + +abstract class $MyRunnableImpl { + factory $MyRunnableImpl({ + required void Function() run, + }) = _$MyRunnableImpl; + + void run(); +} + +class _$MyRunnableImpl implements $MyRunnableImpl { + _$MyRunnableImpl({ + required void Function() run, + }) : _run = run; + + final void Function() _run; + + void run() { + return _run(); + } +} + +class $MyRunnableType extends jni.JObjType { + const $MyRunnableType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;"; + + @override + MyRunnable fromRef(jni.JObjectPtr ref) => MyRunnable.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableType) && other is $MyRunnableType; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnableRunner +class MyRunnableRunner extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnableRunner.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableRunnerType(); + static final _get_error = jniLookup< + ffi.NativeFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>>("get_MyRunnableRunner__error") + .asFunction< + jni.JniResult Function( + jni.JObjectPtr, + )>(); + + static final _set_error = jniLookup< + ffi.NativeFunction< + jni.JniResult Function(jni.JObjectPtr, + ffi.Pointer)>>("set_MyRunnableRunner__error") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer)>(); + + /// from: public java.lang.Throwable error + /// The returned object must be deleted after use, by calling the `delete` method. + jni.JObject get error => + const jni.JObjectType().fromRef(_get_error(reference).object); + + /// from: public java.lang.Throwable error + /// The returned object must be deleted after use, by calling the `delete` method. + set error(jni.JObject value) => + _set_error(reference, value.reference).check(); + + static final _new0 = jniLookup< + ffi + .NativeFunction)>>( + "MyRunnableRunner__new0") + .asFunction)>(); + + /// from: public void (com.github.dart_lang.jnigen.interfaces.MyRunnable runnable) + /// The returned object must be deleted after use, by calling the `delete` method. + factory MyRunnableRunner( + MyRunnable runnable, + ) { + return MyRunnableRunner.fromRef(_new0(runnable.reference).object); + } + + static final _runOnSameThread = jniLookup< + ffi + .NativeFunction)>>( + "MyRunnableRunner__runOnSameThread") + .asFunction)>(); + + /// from: public void runOnSameThread() + void runOnSameThread() { + return _runOnSameThread(reference).check(); + } + + static final _runOnAnotherThread = jniLookup< + ffi + .NativeFunction)>>( + "MyRunnableRunner__runOnAnotherThread") + .asFunction)>(); + + /// from: public void runOnAnotherThread() + void runOnAnotherThread() { + return _runOnAnotherThread(reference).check(); + } +} + +class $MyRunnableRunnerType extends jni.JObjType { + const $MyRunnableRunnerType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnableRunner;"; + + @override + MyRunnableRunner fromRef(jni.JObjectPtr ref) => MyRunnableRunner.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableRunnerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableRunnerType) && + other is $MyRunnableRunnerType; + } +} + /// from: com.github.dart_lang.jnigen.annotations.JsonSerializable$Case class JsonSerializable_Case extends jni.JObject { @override diff --git a/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart b/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart index 9ca08571..7b36cdd3 100644 --- a/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart +++ b/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart @@ -3180,42 +3180,46 @@ class MyInterface<$T extends jni.JObject> extends jni.JObject { int $p, $MethodInvocation $i, ) { - final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); - final $a = $i.args; - if ($d == r"voidCallback(Ljava/lang/String;)V") { - _$impls[$p]!.voidCallback( - $a[0].castTo(const jni.JStringType(), deleteOriginal: true), - ); - return jni.nullptr; - } - if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { - final $r = _$impls[$p]!.stringCallback( - $a[0].castTo(const jni.JStringType(), deleteOriginal: true), - ); - return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); - } - if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { - final $r = _$impls[$p]!.varCallback( - $a[0].castTo(_$impls[$p]!.T, deleteOriginal: true), - ); - return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); - } - if ($d == r"manyPrimitives(IZCD)J") { - final $r = _$impls[$p]!.manyPrimitives( - $a[0] - .castTo(const jni.JIntegerType(), deleteOriginal: true) - .intValue(deleteOriginal: true), - $a[1] - .castTo(const jni.JBooleanType(), deleteOriginal: true) - .booleanValue(deleteOriginal: true), - $a[2] - .castTo(const jni.JCharacterType(), deleteOriginal: true) - .charValue(deleteOriginal: true), - $a[3] - .castTo(const jni.JDoubleType(), deleteOriginal: true) - .doubleValue(deleteOriginal: true), - ); - return jni.JLong($r).toPointer(); + try { + final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); + final $a = $i.args; + if ($d == r"voidCallback(Ljava/lang/String;)V") { + _$impls[$p]!.voidCallback( + $a[0].castTo(const jni.JStringType(), deleteOriginal: true), + ); + return jni.nullptr; + } + if ($d == r"stringCallback(Ljava/lang/String;)Ljava/lang/String;") { + final $r = _$impls[$p]!.stringCallback( + $a[0].castTo(const jni.JStringType(), deleteOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"varCallback(Ljava/lang/Object;)Ljava/lang/Object;") { + final $r = _$impls[$p]!.varCallback( + $a[0].castTo(_$impls[$p]!.T, deleteOriginal: true), + ); + return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer(); + } + if ($d == r"manyPrimitives(IZCD)J") { + final $r = _$impls[$p]!.manyPrimitives( + $a[0] + .castTo(const jni.JIntegerType(), deleteOriginal: true) + .intValue(deleteOriginal: true), + $a[1] + .castTo(const jni.JBooleanType(), deleteOriginal: true) + .booleanValue(deleteOriginal: true), + $a[2] + .castTo(const jni.JCharacterType(), deleteOriginal: true) + .charValue(deleteOriginal: true), + $a[3] + .castTo(const jni.JDoubleType(), deleteOriginal: true) + .doubleValue(deleteOriginal: true), + ); + return jni.JLong($r).toPointer(); + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); } return jni.nullptr; } @@ -3452,6 +3456,231 @@ class $MyInterfaceConsumerType extends jni.JObjType { } } +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnable +class MyRunnable extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnable.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = + jni.Jni.findJClass(r"com/github/dart_lang/jnigen/interfaces/MyRunnable"); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableType(); + static final _id_run = + jni.Jni.accessors.getMethodIDOf(_class.reference, r"run", r"()V"); + + /// from: public abstract void run() + void run() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_run, jni.JniCallType.voidType, []).check(); + } + + /// Maps a specific port to the implemented interface. + static final Map _$impls = {}; + ReceivePort? _$p; + + static jni.JObjectPtr _$invoke( + int port, + jni.JObjectPtr descriptor, + jni.JObjectPtr args, + ) { + return _$invokeMethod( + port, + $MethodInvocation.fromAddresses( + 0, + descriptor.address, + args.address, + ), + ); + } + + static final ffi.Pointer< + ffi.NativeFunction< + jni.JObjectPtr Function( + ffi.Uint64, jni.JObjectPtr, jni.JObjectPtr)>> + _$invokePointer = ffi.Pointer.fromFunction(_$invoke); + + static ffi.Pointer _$invokeMethod( + int $p, + $MethodInvocation $i, + ) { + try { + final $d = $i.methodDescriptor.toDartString(deleteOriginal: true); + final $a = $i.args; + if ($d == r"run()V") { + _$impls[$p]!.run(); + return jni.nullptr; + } + } catch (e) { + return ProtectedJniExtensions.newDartException(e.toString()); + } + return jni.nullptr; + } + + factory MyRunnable.implement( + $MyRunnableImpl $impl, + ) { + final $p = ReceivePort(); + final $x = MyRunnable.fromRef( + ProtectedJniExtensions.newPortProxy( + r"com.github.dart_lang.jnigen.interfaces.MyRunnable", + $p, + _$invokePointer, + ), + ).._$p = $p; + final $a = $p.sendPort.nativePort; + _$impls[$a] = $impl; + $p.listen(($m) { + if ($m == null) { + _$impls.remove($p.sendPort.nativePort); + $p.close(); + return; + } + final $i = $MethodInvocation.fromMessage($m); + final $r = _$invokeMethod($p.sendPort.nativePort, $i); + ProtectedJniExtensions.returnResult($i.result, $r); + }); + return $x; + } +} + +abstract class $MyRunnableImpl { + factory $MyRunnableImpl({ + required void Function() run, + }) = _$MyRunnableImpl; + + void run(); +} + +class _$MyRunnableImpl implements $MyRunnableImpl { + _$MyRunnableImpl({ + required void Function() run, + }) : _run = run; + + final void Function() _run; + + void run() { + return _run(); + } +} + +class $MyRunnableType extends jni.JObjType { + const $MyRunnableType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;"; + + @override + MyRunnable fromRef(jni.JObjectPtr ref) => MyRunnable.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableType) && other is $MyRunnableType; + } +} + +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnableRunner +class MyRunnableRunner extends jni.JObject { + @override + late final jni.JObjType $type = type; + + MyRunnableRunner.fromRef( + jni.JObjectPtr ref, + ) : super.fromRef(ref); + + static final _class = jni.Jni.findJClass( + r"com/github/dart_lang/jnigen/interfaces/MyRunnableRunner"); + + /// The type which includes information such as the signature of this class. + static const type = $MyRunnableRunnerType(); + static final _id_error = jni.Jni.accessors.getFieldIDOf( + _class.reference, + r"error", + r"Ljava/lang/Throwable;", + ); + + /// from: public java.lang.Throwable error + /// The returned object must be deleted after use, by calling the `delete` method. + jni.JObject get error => const jni.JObjectType().fromRef(jni.Jni.accessors + .getField(reference, _id_error, jni.JniCallType.objectType) + .object); + + /// from: public java.lang.Throwable error + /// The returned object must be deleted after use, by calling the `delete` method. + set error(jni.JObject value) => + jni.Jni.env.SetObjectField(reference, _id_error, value.reference); + + static final _id_new0 = jni.Jni.accessors.getMethodIDOf(_class.reference, + r"", r"(Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;)V"); + + /// from: public void (com.github.dart_lang.jnigen.interfaces.MyRunnable runnable) + /// The returned object must be deleted after use, by calling the `delete` method. + factory MyRunnableRunner( + MyRunnable runnable, + ) { + return MyRunnableRunner.fromRef(jni.Jni.accessors.newObjectWithArgs( + _class.reference, _id_new0, [runnable.reference]).object); + } + + static final _id_runOnSameThread = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"runOnSameThread", r"()V"); + + /// from: public void runOnSameThread() + void runOnSameThread() { + return jni.Jni.accessors.callMethodWithArgs( + reference, _id_runOnSameThread, jni.JniCallType.voidType, []).check(); + } + + static final _id_runOnAnotherThread = jni.Jni.accessors + .getMethodIDOf(_class.reference, r"runOnAnotherThread", r"()V"); + + /// from: public void runOnAnotherThread() + void runOnAnotherThread() { + return jni.Jni.accessors.callMethodWithArgs(reference, + _id_runOnAnotherThread, jni.JniCallType.voidType, []).check(); + } +} + +class $MyRunnableRunnerType extends jni.JObjType { + const $MyRunnableRunnerType(); + + @override + String get signature => + r"Lcom/github/dart_lang/jnigen/interfaces/MyRunnableRunner;"; + + @override + MyRunnableRunner fromRef(jni.JObjectPtr ref) => MyRunnableRunner.fromRef(ref); + + @override + jni.JObjType get superType => const jni.JObjectType(); + + @override + final superCount = 1; + + @override + int get hashCode => ($MyRunnableRunnerType).hashCode; + + @override + bool operator ==(Object other) { + return other.runtimeType == ($MyRunnableRunnerType) && + other is $MyRunnableRunnerType; + } +} + /// from: com.github.dart_lang.jnigen.annotations.JsonSerializable$Case class JsonSerializable_Case extends jni.JObject { @override diff --git a/jnigen/test/simple_package_test/generate.dart b/jnigen/test/simple_package_test/generate.dart index 446cfb28..9f598888 100644 --- a/jnigen/test/simple_package_test/generate.dart +++ b/jnigen/test/simple_package_test/generate.dart @@ -32,6 +32,8 @@ var javaFiles = [ join(javaPrefix, 'generics', 'StringStack.java'), join(javaPrefix, 'generics', 'StringValuedMap.java'), join(javaPrefix, 'generics', 'StringKeyedMap.java'), + join(javaPrefix, 'interfaces', 'MyRunnable.java'), + join(javaPrefix, 'interfaces', 'MyRunnableRunner.java'), join(javaPrefix, 'interfaces', 'MyInterface.java'), join(javaPrefix, 'interfaces', 'MyInterfaceConsumer.java'), join(javaPrefix, 'annotations', 'JsonSerializable.java'), diff --git a/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java b/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java new file mode 100644 index 00000000..4a39f815 --- /dev/null +++ b/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java @@ -0,0 +1,9 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.github.dart_lang.jnigen.interfaces; + +public interface MyRunnable { + void run(); +} diff --git a/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java b/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java new file mode 100644 index 00000000..2903f37e --- /dev/null +++ b/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java @@ -0,0 +1,28 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.github.dart_lang.jnigen.interfaces; + +public class MyRunnableRunner { + final MyRunnable runnable; + + public Throwable error; + + public MyRunnableRunner(MyRunnable runnable) { + this.runnable = runnable; + } + + public void runOnSameThread() { + try { + runnable.run(); + } catch (Throwable e) { + error = e; + } + } + + public void runOnAnotherThread() { + var thread = new Thread(this::runOnSameThread); + thread.start(); + } +} diff --git a/jnigen/test/simple_package_test/runtime_test_registrant.dart b/jnigen/test/simple_package_test/runtime_test_registrant.dart index cae97587..07ed1d3a 100644 --- a/jnigen/test/simple_package_test/runtime_test_registrant.dart +++ b/jnigen/test/simple_package_test/runtime_test_registrant.dart @@ -24,8 +24,8 @@ void _runJavaGC() { final pid = bean.callMethodByName('getPid', '()J', []); ProcessResult result; do { - sleep(const Duration(milliseconds: 100)); result = Process.runSync('jcmd', [pid.toString(), 'GC.run']); + sleep(const Duration(milliseconds: 100)); } while (result.exitCode != 0); } @@ -624,6 +624,50 @@ void registerTests(String groupName, TestRunnerCallback test) { expect(MyInterface.$impls, isEmpty); }); } + group('Dart exceptions are handled', () { + for (final exception in [UnimplementedError(), 'Hello!']) { + for (final sameThread in [true, false]) { + test( + 'on ${sameThread ? 'the same thread' : 'another thread'}' + ' throwing $exception', () async { + final runnable = MyRunnable.implement( + $MyRunnableImpl( + run: () { + throw exception; + }, + ), + ); + final runner = MyRunnableRunner(runnable); + if (sameThread) { + runner.runOnSameThread(); + } else { + runner.runOnAnotherThread(); + } + while (runner.error.isNull) { + await Future.delayed(const Duration(milliseconds: 100)); + } + expect( + Jni.env.IsInstanceOf( + runner.error.reference, + Jni.findClass('java/lang/reflect/UndeclaredThrowableException'), + ), + isTrue, + ); + final cause = runner.error.callMethodByName( + 'getCause', '()Ljava/lang/Throwable;', []); + expect( + Jni.env.IsInstanceOf( + cause.reference, + Jni.findClass( + 'com/github/dart_lang/jni/PortProxy\$DartException'), + ), + isTrue, + ); + expect(cause.toString(), contains(exception.toString())); + }); + } + } + }); }); group('$groupName (load tests)', () {