[jnigen] Throw DartExceptions in Java (https://github.com/dart-lang/jnigen/issues/376)
diff --git a/pkgs/jni/example/android/app/build.gradle b/pkgs/jni/example/android/app/build.gradle index 3c6742c..fbcc356 100644 --- a/pkgs/jni/example/android/app/build.gradle +++ b/pkgs/jni/example/android/app/build.gradle
@@ -8,7 +8,7 @@ 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/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java index ff9c076..3caf02a 100644 --- a/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java +++ b/pkgs/jni/java/src/main/java/com/github/dart_lang/jni/PortProxy.java
@@ -73,10 +73,19 @@ 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/pkgs/jni/lib/src/jni.dart b/pkgs/jni/lib/src/jni.dart index 2957105..d5495bc 100644 --- a/pkgs/jni/lib/src/jni.dart +++ b/pkgs/jni/lib/src/jni.dart
@@ -299,6 +299,13 @@ 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 @@ .object; } - /// Return the result of a callback.. + /// Returns the result of a callback.. static void returnResult( Pointer<CallbackResult> result, JObjectPtr object) async { Jni._bindings.resultFor(result, object); @@ -334,28 +341,30 @@ /// 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<Utf8>().toDartString(); - ReleaseStringUTFChars(jstringPtr, chars); + final result = chars.cast<Utf16>().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<Char>(); - final result = NewStringUTF(utf); - malloc.free(utf); + final utf = s.toNativeUtf16(allocator: arena).cast<Uint16>(); + final result = NewString(utf, s.length); + if (utf == nullptr) { + throw 'Fatal: cannot convert string to Java string: $s'; + } return result; });
diff --git a/pkgs/jni/lib/src/lang/jstring.dart b/pkgs/jni/lib/src/lang/jstring.dart index 5bfcce5..f1df76c 100644 --- a/pkgs/jni/lib/src/lang/jstring.dart +++ b/pkgs/jni/lib/src/lang/jstring.dart
@@ -47,20 +47,11 @@ /// 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<Uint16>(); - 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/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart b/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart index bdd6ab7..892f69e 100644 --- a/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart +++ b/pkgs/jni/lib/src/third_party/jni_bindings_generated.dart
@@ -178,22 +178,19 @@ late final _InitDartApiDL = _InitDartApiDLPtr.asFunction<int Function(ffi.Pointer<ffi.Void>)>(); - void resultFor( - ffi.Pointer<CallbackResult> 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<CallbackResult>, JObjectPtr)>>('resultFor'); - late final _resultFor = _resultForPtr - .asFunction<void Function(ffi.Pointer<CallbackResult>, JObjectPtr)>(); + late final _DartException__ctorPtr = + _lookup<ffi.NativeFunction<JniResult Function(JStringPtr)>>( + 'DartException__ctor'); + late final _DartException__ctor = + _DartException__ctorPtr.asFunction<JniResult Function(JStringPtr)>(); JniResult PortContinuation__ctor( int j, @@ -228,6 +225,23 @@ late final _PortProxy__newInstance = _PortProxy__newInstancePtr.asFunction< JniResult Function(JObjectPtr, int, int)>(); + void resultFor( + ffi.Pointer<CallbackResult> result, + JObjectPtr object, + ) { + return _resultFor( + result, + object, + ); + } + + late final _resultForPtr = _lookup< + ffi.NativeFunction< + ffi.Void Function( + ffi.Pointer<CallbackResult>, JObjectPtr)>>('resultFor'); + late final _resultFor = _resultForPtr + .asFunction<void Function(ffi.Pointer<CallbackResult>, JObjectPtr)>(); + ffi.Pointer<GlobalJniEnvStruct> GetGlobalEnv() { return _GetGlobalEnv(); }
diff --git a/pkgs/jni/src/dartjni.c b/pkgs/jni/src/dartjni.c index dc595a9..7c5951b 100644 --- a/pkgs/jni/src/dartjni.c +++ b/pkgs/jni/src/dartjni.c
@@ -569,6 +569,29 @@ 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, "<init>", + "(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/pkgs/jni/src/dartjni.h b/pkgs/jni/src/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jni/src/dartjni.h +++ b/pkgs/jni/src/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/android_test_runner/android/app/build.gradle b/pkgs/jnigen/android_test_runner/android/app/build.gradle index e0c777f..58cd27a 100644 --- a/pkgs/jnigen/android_test_runner/android/app/build.gradle +++ b/pkgs/jnigen/android_test_runner/android/app/build.gradle
@@ -8,7 +8,7 @@ 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/pkgs/jnigen/example/in_app_java/android/app/build.gradle b/pkgs/jnigen/example/in_app_java/android/app/build.gradle index 8f38e43..59ebf16 100644 --- a/pkgs/jnigen/example/in_app_java/android/app/build.gradle +++ b/pkgs/jnigen/example/in_app_java/android/app/build.gradle
@@ -8,7 +8,7 @@ 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/pkgs/jnigen/example/in_app_java/src/android_utils/dartjni.h b/pkgs/jnigen/example/in_app_java/src/android_utils/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jnigen/example/in_app_java/src/android_utils/dartjni.h +++ b/pkgs/jnigen/example/in_app_java/src/android_utils/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/example/kotlin_plugin/example/android/app/build.gradle b/pkgs/jnigen/example/kotlin_plugin/example/android/app/build.gradle index f371e65..7f1cb3e 100644 --- a/pkgs/jnigen/example/kotlin_plugin/example/android/app/build.gradle +++ b/pkgs/jnigen/example/kotlin_plugin/example/android/app/build.gradle
@@ -8,7 +8,7 @@ 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/pkgs/jnigen/example/kotlin_plugin/src/dartjni.h b/pkgs/jnigen/example/kotlin_plugin/src/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jnigen/example/kotlin_plugin/src/dartjni.h +++ b/pkgs/jnigen/example/kotlin_plugin/src/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/example/notification_plugin/example/android/app/build.gradle b/pkgs/jnigen/example/notification_plugin/example/android/app/build.gradle index ee3c62f..7f66900 100644 --- a/pkgs/jnigen/example/notification_plugin/example/android/app/build.gradle +++ b/pkgs/jnigen/example/notification_plugin/example/android/app/build.gradle
@@ -8,7 +8,7 @@ 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/pkgs/jnigen/example/notification_plugin/src/dartjni.h b/pkgs/jnigen/example/notification_plugin/src/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jnigen/example/notification_plugin/src/dartjni.h +++ b/pkgs/jnigen/example/notification_plugin/src/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/build.gradle b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/build.gradle index 162ad5b..c5791ba 100644 --- a/pkgs/jnigen/example/pdfbox_plugin/example/android/app/build.gradle +++ b/pkgs/jnigen/example/pdfbox_plugin/example/android/app/build.gradle
@@ -8,7 +8,7 @@ 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/pkgs/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h +++ b/pkgs/jnigen/example/pdfbox_plugin/src/third_party/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/lib/src/bindings/dart_generator.dart b/pkgs/jnigen/lib/src/bindings/dart_generator.dart index 3bc72cc..d21665c 100644 --- a/pkgs/jnigen/lib/src/bindings/dart_generator.dart +++ b/pkgs/jnigen/lib/src/bindings/dart_generator.dart
@@ -439,14 +439,18 @@ 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 @@ ).._\$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 @@ 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/pkgs/jnigen/lib/src/config/experiments.dart b/pkgs/jnigen/lib/src/config/experiments.dart index d0eb39d..6bb65c1 100644 --- a/pkgs/jnigen/lib/src/config/experiments.dart +++ b/pkgs/jnigen/lib/src/config/experiments.dart
@@ -31,7 +31,7 @@ } 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/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h +++ b/pkgs/jnigen/test/jackson_core_test/third_party/c_based/c_bindings/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h +++ b/pkgs/jnigen/test/kotlin_test/c_based/c_bindings/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/test/regenerate_examples_test.dart b/pkgs/jnigen/test/regenerate_examples_test.dart index 5afeebe..35ab2e0 100644 --- a/pkgs/jnigen/test/regenerate_examples_test.dart +++ b/pkgs/jnigen/test/regenerate_examples_test.dart
@@ -29,7 +29,7 @@ {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/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h index 0a7f669..8f1dc74 100644 --- a/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h +++ b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/dartjni.h
@@ -410,7 +410,8 @@ 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 @@ JniResult PortProxy__newInstance(jobject binaryName, int64_t port, int64_t functionPtr); + +FFI_PLUGIN_EXPORT void resultFor(CallbackResult* result, jobject object);
diff --git a/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c index 62b150e..20c7e7e 100644 --- a/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c +++ b/pkgs/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c
@@ -2786,6 +2786,111 @@ 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, "<init>", + "(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/pkgs/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart b/pkgs/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart index cd47f44..5154b75 100644 --- a/pkgs/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart +++ b/pkgs/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart
@@ -3371,42 +3371,46 @@ 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 @@ } } +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnable +class MyRunnable extends jni.JObject { + @override + late final jni.JObjType<MyRunnable> $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<jni.JniResult Function(ffi.Pointer<ffi.Void>)>>( + "MyRunnable__run") + .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>(); + + /// from: public abstract void run() + void run() { + return _run(reference).check(); + } + + /// Maps a specific port to the implemented interface. + static final Map<int, $MyRunnableImpl> _$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<ffi.Void> _$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<MyRunnable> { + 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<MyRunnableRunner> $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<ffi.Void>)>>("set_MyRunnableRunner__error") + .asFunction< + jni.JniResult Function(jni.JObjectPtr, ffi.Pointer<ffi.Void>)>(); + + /// 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<jni.JniResult Function(ffi.Pointer<ffi.Void>)>>( + "MyRunnableRunner__new0") + .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>(); + + /// from: public void <init>(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<jni.JniResult Function(ffi.Pointer<ffi.Void>)>>( + "MyRunnableRunner__runOnSameThread") + .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>(); + + /// from: public void runOnSameThread() + void runOnSameThread() { + return _runOnSameThread(reference).check(); + } + + static final _runOnAnotherThread = jniLookup< + ffi + .NativeFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>>( + "MyRunnableRunner__runOnAnotherThread") + .asFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>(); + + /// from: public void runOnAnotherThread() + void runOnAnotherThread() { + return _runOnAnotherThread(reference).check(); + } +} + +class $MyRunnableRunnerType extends jni.JObjType<MyRunnableRunner> { + 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/pkgs/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart b/pkgs/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart index 9ca0857..7b36cdd 100644 --- a/pkgs/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart +++ b/pkgs/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart
@@ -3180,42 +3180,46 @@ 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 @@ } } +/// from: com.github.dart_lang.jnigen.interfaces.MyRunnable +class MyRunnable extends jni.JObject { + @override + late final jni.JObjType<MyRunnable> $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<int, $MyRunnableImpl> _$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<ffi.Void> _$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<MyRunnable> { + 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<MyRunnableRunner> $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"<init>", r"(Lcom/github/dart_lang/jnigen/interfaces/MyRunnable;)V"); + + /// from: public void <init>(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<MyRunnableRunner> { + 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/pkgs/jnigen/test/simple_package_test/generate.dart b/pkgs/jnigen/test/simple_package_test/generate.dart index 446cfb2..9f59888 100644 --- a/pkgs/jnigen/test/simple_package_test/generate.dart +++ b/pkgs/jnigen/test/simple_package_test/generate.dart
@@ -32,6 +32,8 @@ 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/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnable.java new file mode 100644 index 0000000..4a39f81 --- /dev/null +++ b/pkgs/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/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java b/pkgs/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/interfaces/MyRunnableRunner.java new file mode 100644 index 0000000..2903f37 --- /dev/null +++ b/pkgs/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/pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart b/pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart index cae9758..07ed1d3 100644 --- a/pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart +++ b/pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart
@@ -24,8 +24,8 @@ final pid = bean.callMethodByName<int>('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 @@ 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<void>.delayed(const Duration(milliseconds: 100)); + } + expect( + Jni.env.IsInstanceOf( + runner.error.reference, + Jni.findClass('java/lang/reflect/UndeclaredThrowableException'), + ), + isTrue, + ); + final cause = runner.error.callMethodByName<JObject>( + '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)', () {