[jnigen] Use Dart 3 class modifiers in `package:jni` (https://github.com/dart-lang/jnigen/issues/398)

diff --git a/pkgs/jni/CHANGELOG.md b/pkgs/jni/CHANGELOG.md
index 15e7e9e..982f626 100644
--- a/pkgs/jni/CHANGELOG.md
+++ b/pkgs/jni/CHANGELOG.md
@@ -14,6 +14,10 @@
 - **Breaking Change**: The default return `callType` of type parameter `int` for
   methods such as `JObject.callMethodByName<int>` is now Java's `long` instead
   of `int` to be consistent with the way arguments work.
+- **Breaking Change**: `JType` is now `sealed`.
+- **Breaking Change**: Primitive types and their type classes are now `final`.
+- **Breaking Change**: `JArray.filled` now uses the generated type class of the
+  `fill` object and not its Java runtime type.
 
 ## 0.7.0
 
diff --git a/pkgs/jni/lib/jni.dart b/pkgs/jni/lib/jni.dart
index ce372ff..5f0f34c 100644
--- a/pkgs/jni/lib/jni.dart
+++ b/pkgs/jni/lib/jni.dart
@@ -66,7 +66,6 @@
 export 'src/types.dart';
 export 'src/jarray.dart';
 export 'src/jobject.dart';
-export 'src/jprimitives.dart';
 export 'src/jreference.dart' show JReferenceUseExtension;
 
 export 'src/lang/lang.dart';
diff --git a/pkgs/jni/lib/src/jarray.dart b/pkgs/jni/lib/src/jarray.dart
index fac1d85..2364312 100644
--- a/pkgs/jni/lib/src/jarray.dart
+++ b/pkgs/jni/lib/src/jarray.dart
@@ -13,7 +13,6 @@
 
 import 'jni.dart';
 import 'jobject.dart';
-import 'jprimitives.dart';
 import 'types.dart';
 
 final class JArrayType<T> extends JObjType<JArray<T>> {
@@ -92,10 +91,9 @@
   /// Creates a [JArray] of the given length with [fill] at each position.
   ///
   /// The [length] must be a non-negative integer.
-  /// The [fill] must be a non-null [JObject].
   static JArray<E> filled<E extends JObject>(int length, E fill) {
-    assert(!fill.isNull, "fill must not be null.");
-    final clazz = fill.getClass();
+    RangeError.checkNotNegative(length);
+    final clazz = fill.$type.getClass();
     final array = JArray<E>.fromRef(
       fill.$type as JObjType<E>,
       Jni.accessors
diff --git a/pkgs/jni/lib/src/jni.dart b/pkgs/jni/lib/src/jni.dart
index 0bc154b..2554041 100644
--- a/pkgs/jni/lib/src/jni.dart
+++ b/pkgs/jni/lib/src/jni.dart
@@ -43,7 +43,7 @@
 }
 
 /// Utilities to spawn and manage JNI.
-abstract class Jni {
+abstract final class Jni {
   static final DynamicLibrary _dylib = _loadDartJniLibrary(dir: _dylibDir);
   static final JniBindings _bindings = JniBindings(_dylib);
   static final _getJniEnvFn = _dylib.lookup<Void>('GetJniEnv');
diff --git a/pkgs/jni/lib/src/jprimitives.dart b/pkgs/jni/lib/src/jprimitives.dart
index 6722557..04448da 100644
--- a/pkgs/jni/lib/src/jprimitives.dart
+++ b/pkgs/jni/lib/src/jprimitives.dart
@@ -6,92 +6,92 @@
 // lowercase.
 // ignore_for_file: camel_case_types
 
-import 'types.dart';
+part of 'types.dart';
 
-abstract class JPrimitive {}
+abstract final class JPrimitive {}
 
-abstract class jbyte extends JPrimitive {
+abstract final class jbyte extends JPrimitive {
   static const type = jbyteType();
 }
 
-class jbyteType extends JType<jbyte> {
+final class jbyteType extends JType<jbyte> {
   const jbyteType();
 
   @override
   final signature = 'B';
 }
 
-abstract class jboolean extends JPrimitive {
+abstract final class jboolean extends JPrimitive {
   static const type = jbooleanType();
 }
 
-class jbooleanType extends JType<jboolean> {
+final class jbooleanType extends JType<jboolean> {
   const jbooleanType();
 
   @override
   final signature = 'Z';
 }
 
-abstract class jchar extends JPrimitive {
+abstract final class jchar extends JPrimitive {
   static const type = jcharType();
 }
 
-class jcharType extends JType<jchar> {
+final class jcharType extends JType<jchar> {
   const jcharType();
 
   @override
   final signature = 'C';
 }
 
-abstract class jshort extends JPrimitive {
+abstract final class jshort extends JPrimitive {
   static const type = jshortType();
 }
 
-class jshortType extends JType<jshort> {
+final class jshortType extends JType<jshort> {
   const jshortType();
 
   @override
   final signature = 'S';
 }
 
-abstract class jint extends JPrimitive {
+abstract final class jint extends JPrimitive {
   static const type = jintType();
 }
 
-class jintType extends JType<jint> {
+final class jintType extends JType<jint> {
   const jintType();
 
   @override
   final signature = 'I';
 }
 
-abstract class jlong extends JPrimitive {
+abstract final class jlong extends JPrimitive {
   static const type = jlongType();
 }
 
-class jlongType extends JType<jlong> {
+final class jlongType extends JType<jlong> {
   const jlongType();
 
   @override
   final signature = 'J';
 }
 
-abstract class jfloat extends JPrimitive {
+abstract final class jfloat extends JPrimitive {
   static const type = jfloatType();
 }
 
-class jfloatType extends JType<jfloat> {
+final class jfloatType extends JType<jfloat> {
   const jfloatType();
 
   @override
   final signature = 'F';
 }
 
-abstract class jdouble extends JPrimitive {
+abstract final class jdouble extends JPrimitive {
   static const type = jdoubleType();
 }
 
-class jdoubleType extends JType<jdouble> {
+final class jdoubleType extends JType<jdouble> {
   const jdoubleType();
 
   @override
diff --git a/pkgs/jni/lib/src/jvalues.dart b/pkgs/jni/lib/src/jvalues.dart
index 84439bf..dc17736 100644
--- a/pkgs/jni/lib/src/jvalues.dart
+++ b/pkgs/jni/lib/src/jvalues.dart
@@ -67,35 +67,35 @@
 
 /// Use this class as wrapper to convert an integer
 /// to Java `int` in jvalues method.
-class JValueInt {
+final class JValueInt {
   int value;
   JValueInt(this.value);
 }
 
 /// Use this class as wrapper to convert an integer
 /// to Java `short` in jvalues method.
-class JValueShort {
+final class JValueShort {
   int value;
   JValueShort(this.value);
 }
 
 /// Use this class as wrapper to convert an integer
 /// to Java `byte` in jvalues method.
-class JValueByte {
+final class JValueByte {
   int value;
   JValueByte(this.value);
 }
 
 /// Use this class as wrapper to convert an double
 /// to Java `float` in jvalues method.
-class JValueFloat {
+final class JValueFloat {
   double value;
   JValueFloat(this.value);
 }
 
 /// Use this class as wrapper to convert an integer
 /// to Java `char` in jvalues method.
-class JValueChar {
+final class JValueChar {
   int value;
   JValueChar(this.value);
   JValueChar.fromString(String s) : value = 0 {
@@ -115,7 +115,7 @@
 ///
 /// Returned value is allocated using provided allocator.
 /// But default allocator may be used for string conversions.
-class JValueArgs {
+final class JValueArgs {
   late Pointer<JValue> values;
   final List<JObjectPtr> createdRefs = [];
 
diff --git a/pkgs/jni/lib/src/nio/jbyte_buffer.dart b/pkgs/jni/lib/src/nio/jbyte_buffer.dart
index 1b0acb2..d5f5488 100644
--- a/pkgs/jni/lib/src/nio/jbyte_buffer.dart
+++ b/pkgs/jni/lib/src/nio/jbyte_buffer.dart
@@ -8,7 +8,6 @@
 import '../accessors.dart';
 import '../jarray.dart';
 import '../jni.dart';
-import '../jprimitives.dart';
 import '../jreference.dart';
 import '../jvalues.dart';
 import '../third_party/generated_bindings.dart';
diff --git a/pkgs/jni/lib/src/types.dart b/pkgs/jni/lib/src/types.dart
index c6f44b6..d560b2d 100644
--- a/pkgs/jni/lib/src/types.dart
+++ b/pkgs/jni/lib/src/types.dart
@@ -7,7 +7,9 @@
 import 'jni.dart';
 import 'jobject.dart';
 
-abstract class JType<T> {
+part 'jprimitives.dart';
+
+sealed class JType<T> {
   const JType();
 
   String get signature;
diff --git a/pkgs/jni/test/jarray_test.dart b/pkgs/jni/test/jarray_test.dart
index 9a9f59c..064bc84 100644
--- a/pkgs/jni/test/jarray_test.dart
+++ b/pkgs/jni/test/jarray_test.dart
@@ -289,11 +289,8 @@
       final string = "abc".toJString()..releasedBy(arena);
       final array = JArray.filled(3, string)..releasedBy(arena);
       expect(
-        () {
-          final _ = JArray.filled(3, JString.fromRef(nullptr))
-            ..releasedBy(arena);
-        },
-        throwsA(isA<AssertionError>()),
+        () => JArray.filled(-3, JString.fromRef(nullptr)),
+        throwsA(isA<RangeError>()),
       );
       expect(array.length, 3);
       expect(array[0].toDartString(releaseOriginal: true), "abc");
diff --git a/pkgs/jnigen/CHANGELOG.md b/pkgs/jnigen/CHANGELOG.md
index 00b2fc1..0056f41 100644
--- a/pkgs/jnigen/CHANGELOG.md
+++ b/pkgs/jnigen/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.8.0-wip
+
+- **Breaking Change**: The generated impl class for interfaces is now an
+  `interface`.
+
 ## 0.7.0
 
 - **Breaking Change** ([#387](https://github.com/dart-lang/jnigen/issues/387)):
diff --git a/pkgs/jnigen/lib/src/bindings/dart_generator.dart b/pkgs/jnigen/lib/src/bindings/dart_generator.dart
index ed52373..9c20692 100644
--- a/pkgs/jnigen/lib/src/bindings/dart_generator.dart
+++ b/pkgs/jnigen/lib/src/bindings/dart_generator.dart
@@ -520,7 +520,7 @@
         '}',
       );
       s.write('''
-abstract class $implClassName$typeParamsDef {
+abstract interface class $implClassName$typeParamsDef {
   factory $implClassName(
     $abstractFactoryArgs
   ) = _$implClassName;
diff --git a/pkgs/jnigen/pubspec.yaml b/pkgs/jnigen/pubspec.yaml
index 3fbd456..35e01bc 100644
--- a/pkgs/jnigen/pubspec.yaml
+++ b/pkgs/jnigen/pubspec.yaml
@@ -4,7 +4,7 @@
 
 name: jnigen
 description: A Dart bindings generator for Java and Kotlin that uses JNI under the hood to interop with Java virtual machine.
-version: 0.7.0
+version: 0.8.0-wip
 repository: https://github.com/dart-lang/jnigen/tree/main/jnigen
 
 environment:
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 1142fd6..7327fcf 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
@@ -3446,7 +3446,7 @@
   static Map<int, $MyInterfaceImpl> get $impls => _$impls;
 }
 
-abstract class $MyInterfaceImpl<$T extends jni.JObject> {
+abstract interface class $MyInterfaceImpl<$T extends jni.JObject> {
   factory $MyInterfaceImpl({
     required jni.JObjType<$T> T,
     required void Function(jni.JString s) voidCallback,
@@ -3743,7 +3743,7 @@
   }
 }
 
-abstract class $MyRunnableImpl {
+abstract interface class $MyRunnableImpl {
   factory $MyRunnableImpl({
     required void Function() run,
   }) = _$MyRunnableImpl;
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 7ac848d..ba02269 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
@@ -3255,7 +3255,7 @@
   static Map<int, $MyInterfaceImpl> get $impls => _$impls;
 }
 
-abstract class $MyInterfaceImpl<$T extends jni.JObject> {
+abstract interface class $MyInterfaceImpl<$T extends jni.JObject> {
   factory $MyInterfaceImpl({
     required jni.JObjType<$T> T,
     required void Function(jni.JString s) voidCallback,
@@ -3550,7 +3550,7 @@
   }
 }
 
-abstract class $MyRunnableImpl {
+abstract interface class $MyRunnableImpl {
   factory $MyRunnableImpl({
     required void Function() run,
   }) = _$MyRunnableImpl;