[jnigen] Check for free in reference getter (https://github.com/dart-lang/jnigen/issues/361)

diff --git a/pkgs/jni/example/pubspec.lock b/pkgs/jni/example/pubspec.lock
index 0824b6e..eb16370 100644
--- a/pkgs/jni/example/pubspec.lock
+++ b/pkgs/jni/example/pubspec.lock
@@ -519,5 +519,5 @@
     source: hosted
     version: "3.1.2"
 sdks:
-  dart: ">=3.1.0 <4.0.0"
+  dart: ">=3.1.0-262.3.beta <4.0.0"
   flutter: ">=2.11.0"
diff --git a/pkgs/jni/example/pubspec.yaml b/pkgs/jni/example/pubspec.yaml
index ce06464..7972e84 100644
--- a/pkgs/jni/example/pubspec.yaml
+++ b/pkgs/jni/example/pubspec.yaml
@@ -18,7 +18,7 @@
 version: 1.0.0+1
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 # Dependencies specify other packages that your package needs in order to work.
 # To automatically upgrade your package dependencies to the latest versions
diff --git a/pkgs/jni/lib/src/jexceptions.dart b/pkgs/jni/lib/src/jexceptions.dart
index 4c9cda0..64b95fc 100644
--- a/pkgs/jni/lib/src/jexceptions.dart
+++ b/pkgs/jni/lib/src/jexceptions.dart
@@ -9,37 +9,38 @@
 abstract class JException implements Exception {}
 
 class UseAfterFreeException implements JException {
-  dynamic object;
-  Pointer<Void> ptr;
-  UseAfterFreeException(this.object, this.ptr);
+  final Pointer<Void> ptr;
+  UseAfterFreeException(this.ptr);
 
   @override
   String toString() {
-    return "use after free on $ptr through $object";
+    return 'Use after free on $ptr.';
   }
 }
 
-class NullJStringException implements JException {
+class JNullException implements JException {
+  const JNullException();
+
   @override
-  String toString() => 'toDartString called on null JString reference';
+  String toString() => 'The reference was null.';
 }
 
 class InvalidJStringException implements JException {
-  Pointer<Void> reference;
+  final Pointer<Void> reference;
   InvalidJStringException(this.reference);
+
   @override
   String toString() => 'Not a valid Java String: '
-      '0x${reference.address.toRadixString(16)}';
+      '0x${reference.address.toRadixString(16)}.';
 }
 
 class DoubleFreeException implements JException {
-  dynamic object;
-  Pointer<Void> ptr;
-  DoubleFreeException(this.object, this.ptr);
+  final Pointer<Void> ptr;
+  DoubleFreeException(this.ptr);
 
   @override
   String toString() {
-    return "double free on $ptr through $object";
+    return 'Double free on $ptr.';
   }
 }
 
@@ -113,9 +114,10 @@
   final String path;
 
   @override
-  String toString() => "Lookup for helper library $path failed.\n"
-      "Please ensure that `dartjni` shared library is built.\n"
-      "Provided jni:setup script can be used to build the shared library."
-      "If the library is already built, ensure that the JVM libraries can be "
-      "loaded from Dart.";
+  String toString() => '''
+Lookup for helper library $path failed.
+Please ensure that `dartjni` shared library is built.
+Provided jni:setup script can be used to build the shared library.
+If the library is already built, ensure that the JVM libraries can be 
+loaded from Dart.''';
 }
diff --git a/pkgs/jni/lib/src/jni.dart b/pkgs/jni/lib/src/jni.dart
index d6836b0..2957105 100644
--- a/pkgs/jni/lib/src/jni.dart
+++ b/pkgs/jni/lib/src/jni.dart
@@ -337,7 +337,7 @@
   /// DeleteLocalRef.
   String toDartString(JStringPtr jstringPtr, {bool deleteOriginal = false}) {
     if (jstringPtr == nullptr) {
-      throw NullJStringException();
+      throw const JNullException();
     }
     final chars = GetStringUTFChars(jstringPtr, nullptr);
     if (chars == nullptr) {
diff --git a/pkgs/jni/lib/src/jobject.dart b/pkgs/jni/lib/src/jobject.dart
index c5e88c1..c0b077b 100644
--- a/pkgs/jni/lib/src/jobject.dart
+++ b/pkgs/jni/lib/src/jobject.dart
@@ -189,7 +189,6 @@
   ///
   /// This may be a subclass of compile-time class.
   JClass getClass() {
-    ensureNotDeleted();
     final classRef = Jni.env.GetObjectClass(reference);
     if (classRef == nullptr) {
       Jni.accessors.throwException(Jni.env.ExceptionOccurred());
@@ -199,28 +198,24 @@
 
   /// Get [JFieldIDPtr] of instance field identified by [fieldName] & [signature].
   JFieldIDPtr getFieldID(String fieldName, String signature) {
-    ensureNotDeleted();
     return _getID(
         Jni.accessors.getFieldID, _class.reference, fieldName, signature);
   }
 
   /// Get [JFieldIDPtr] of static field identified by [fieldName] & [signature].
   JFieldIDPtr getStaticFieldID(String fieldName, String signature) {
-    ensureNotDeleted();
     return _getID<jfieldID_>(
         Jni.accessors.getStaticFieldID, _class.reference, fieldName, signature);
   }
 
   /// Get [JMethodIDPtr] of instance method [methodName] with [signature].
   JMethodIDPtr getMethodID(String methodName, String signature) {
-    ensureNotDeleted();
     return _getID<jmethodID_>(
         Jni.accessors.getMethodID, _class.reference, methodName, signature);
   }
 
   /// Get [JMethodIDPtr] of static method [methodName] with [signature].
   JMethodIDPtr getStaticMethodID(String methodName, String signature) {
-    ensureNotDeleted();
     return _getID<jmethodID_>(Jni.accessors.getStaticMethodID, _class.reference,
         methodName, signature);
   }
@@ -235,7 +230,6 @@
   /// If [T] is String or [JObject], required conversions are performed and
   /// final value is returned.
   T getField<T>(JFieldIDPtr fieldID, [int? callType]) {
-    ensureNotDeleted();
     if (callType == JniCallType.voidType) {
       throw ArgumentError("void is not a valid field type.");
     }
@@ -258,7 +252,6 @@
     if (callType == JniCallType.voidType) {
       throw ArgumentError("void is not a valid field type.");
     }
-    ensureNotDeleted();
     return _getField<T>(callType,
         (ct) => Jni.accessors.getStaticField(_class.reference, fieldID, ct));
   }
@@ -278,7 +271,6 @@
   ///
   /// See [getField] for an explanation about [callType] and return type [T].
   T callMethod<T>(JMethodIDPtr methodID, List<dynamic> args, [int? callType]) {
-    ensureNotDeleted();
     return _callMethod<T>(callType, args,
         (ct, jvs) => Jni.accessors.callMethod(reference, methodID, ct, jvs));
   }
@@ -296,7 +288,6 @@
   /// more details about [args] and [callType].
   T callStaticMethod<T>(JMethodIDPtr methodID, List<dynamic> args,
       [int? callType]) {
-    ensureNotDeleted();
     return _callMethod<T>(
         callType,
         args,
@@ -317,8 +308,9 @@
   T castTo<T extends JObject>(JObjType<T> type, {bool deleteOriginal = false}) {
     if (deleteOriginal) {
       _jClass?.delete();
+      final ret = type.fromRef(reference);
       setAsDeleted();
-      return type.fromRef(reference);
+      return ret;
     }
     final newRef = Jni.env.NewGlobalRef(reference);
     return type.fromRef(newRef);
@@ -360,28 +352,24 @@
 
   /// Get [JFieldIDPtr] of static field [fieldName] with [signature].
   JFieldIDPtr getStaticFieldID(String fieldName, String signature) {
-    ensureNotDeleted();
     return _getID<jfieldID_>(
         Jni.accessors.getStaticFieldID, reference, fieldName, signature);
   }
 
   /// Get [JMethodIDPtr] of static method [methodName] with [signature].
   JMethodIDPtr getStaticMethodID(String methodName, String signature) {
-    ensureNotDeleted();
     return _getID<jmethodID_>(
         Jni.accessors.getStaticMethodID, reference, methodName, signature);
   }
 
   /// Get [JFieldIDPtr] of field [fieldName] with [signature].
   JFieldIDPtr getFieldID(String fieldName, String signature) {
-    ensureNotDeleted();
     return _getID<jfieldID_>(
         Jni.accessors.getFieldID, reference, fieldName, signature);
   }
 
   /// Get [JMethodIDPtr] of method [methodName] with [signature].
   JMethodIDPtr getMethodID(String methodName, String signature) {
-    ensureNotDeleted();
     return _getID<jmethodID_>(
         Jni.accessors.getMethodID, reference, methodName, signature);
   }
@@ -396,7 +384,6 @@
     if (callType == JniCallType.voidType) {
       throw ArgumentError("void is not a valid field type.");
     }
-    ensureNotDeleted();
     return _getField<T>(
         callType, (ct) => Jni.accessors.getStaticField(reference, fieldID, ct));
   }
@@ -415,7 +402,6 @@
   /// about [args] and [callType].
   T callStaticMethod<T>(JMethodIDPtr methodID, List<dynamic> args,
       [int? callType]) {
-    ensureNotDeleted();
     return _callMethod<T>(
         callType,
         args,
@@ -434,7 +420,6 @@
 
   /// Create a new instance of this class with [ctor] and [args].
   JObject newInstance(JMethodIDPtr ctor, List<dynamic> args) => using((arena) {
-        ensureNotDeleted();
         final jArgs = JValueArgs(args, arena);
         final res =
             Jni.accessors.newObject(reference, ctor, jArgs.values).object;
diff --git a/pkgs/jni/lib/src/jreference.dart b/pkgs/jni/lib/src/jreference.dart
index 9430336..973b3f3 100644
--- a/pkgs/jni/lib/src/jreference.dart
+++ b/pkgs/jni/lib/src/jreference.dart
@@ -11,28 +11,37 @@
 import 'jni.dart';
 
 extension ProtectedJReference on JReference {
-  void ensureNotDeleted() {
-    if (_deleted) throw UseAfterFreeException(this, reference);
-  }
-
   void setAsDeleted() {
     if (_deleted) {
-      throw DoubleFreeException(this, reference);
+      throw DoubleFreeException(_reference);
     }
     _deleted = true;
     JReference._finalizer.detach(this);
   }
+
+  void ensureNotNull() {
+    if (isNull) {
+      throw const JNullException();
+    }
+  }
+
+  /// Similar to [reference].
+  ///
+  /// Detaches the finalizer so the underlying pointer will not be deleted.
+  JObjectPtr toPointer() {
+    setAsDeleted();
+    return _reference;
+  }
 }
 
 /// A class which holds one or more JNI references, and has a `delete` operation
 /// which disposes the reference(s).
 abstract class JReference implements Finalizable {
-  //TODO(PR): Is it safe to cast void *f (void *) to void f (void *)?
   static final _finalizer =
       NativeFinalizer(Jni.env.ptr.ref.DeleteGlobalRef.cast());
 
-  JReference.fromRef(this.reference) {
-    _finalizer.attach(this, reference, detach: this);
+  JReference.fromRef(this._reference) {
+    _finalizer.attach(this, _reference, detach: this);
   }
 
   bool _deleted = false;
@@ -43,15 +52,26 @@
   /// Returns whether this object is deleted.
   bool get isDeleted => _deleted;
 
-  /// Deletes the underlying JNI reference. Further uses will throw
-  /// [UseAfterFreeException].
+  /// Deletes the underlying JNI reference.
+  ///
+  /// Further uses will throw [UseAfterFreeException].
   void delete() {
     setAsDeleted();
-    Jni.env.DeleteGlobalRef(reference);
+    Jni.env.DeleteGlobalRef(_reference);
   }
 
   /// The underlying JNI global object reference.
-  final JObjectPtr reference;
+  ///
+  /// Throws [UseAfterFreeException] if the object is previously deleted.
+  ///
+  /// Be careful when storing this reference in a variable, since the underlying
+  /// object might get deleted.
+  JObjectPtr get reference {
+    if (_deleted) throw UseAfterFreeException(_reference);
+    return _reference;
+  }
+
+  final JObjectPtr _reference;
 
   /// Registers this object to be deleted at the end of [arena]'s lifetime.
   void deletedIn(Arena arena) => arena.onReleaseAll(delete);
@@ -61,7 +81,6 @@
   /// Applies [callback] on [this] object and then delete the underlying JNI
   /// reference, returning the result of [callback].
   R use<R>(R Function(T) callback) {
-    ensureNotDeleted();
     try {
       final result = callback(this);
       delete();
diff --git a/pkgs/jni/lib/src/lang/jboolean.dart b/pkgs/jni/lib/src/lang/jboolean.dart
index 03d5304..04f4e7c 100644
--- a/pkgs/jni/lib/src/lang/jboolean.dart
+++ b/pkgs/jni/lib/src/lang/jboolean.dart
@@ -4,6 +4,7 @@
 
 import '../accessors.dart';
 import '../jobject.dart';
+import '../jreference.dart';
 import '../jni.dart';
 import '../third_party/generated_bindings.dart';
 import '../types.dart';
@@ -56,6 +57,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"booleanValue", r"()Z");
 
   bool booleanValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _booleanValueId, JniCallType.booleanType, []).boolean;
     if (deleteOriginal) {
diff --git a/pkgs/jni/lib/src/lang/jcharacter.dart b/pkgs/jni/lib/src/lang/jcharacter.dart
index 6ab76cf..0678706 100644
--- a/pkgs/jni/lib/src/lang/jcharacter.dart
+++ b/pkgs/jni/lib/src/lang/jcharacter.dart
@@ -1,6 +1,7 @@
 import '../accessors.dart';
 import '../jni.dart';
 import '../jobject.dart';
+import '../jreference.dart';
 import '../jvalues.dart';
 import '../third_party/generated_bindings.dart';
 import '../types.dart';
@@ -54,6 +55,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"charValue", r"()C");
 
   int charValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _charValueId, JniCallType.charType, []).char;
     if (deleteOriginal) {
diff --git a/pkgs/jni/lib/src/lang/jnumber.dart b/pkgs/jni/lib/src/lang/jnumber.dart
index cab3033..a468147 100644
--- a/pkgs/jni/lib/src/lang/jnumber.dart
+++ b/pkgs/jni/lib/src/lang/jnumber.dart
@@ -5,6 +5,7 @@
 import '../accessors.dart';
 import '../jni.dart';
 import '../jobject.dart';
+import '../jreference.dart';
 import '../third_party/generated_bindings.dart';
 import '../types.dart';
 import 'jboolean.dart';
@@ -64,6 +65,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"intValue", r"()I");
 
   int intValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _intValueId, JniCallType.intType, []).integer;
     if (deleteOriginal) {
@@ -76,6 +78,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"longValue", r"()J");
 
   int longValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _longValueId, JniCallType.longType, []).long;
     if (deleteOriginal) {
@@ -88,6 +91,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"floatValue", r"()F");
 
   double floatValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _floatValueId, JniCallType.floatType, []).float;
     if (deleteOriginal) {
@@ -100,6 +104,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"doubleValue", r"()D");
 
   double doubleValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _doubleValueId, JniCallType.doubleType, []).doubleFloat;
     if (deleteOriginal) {
@@ -112,6 +117,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"byteValue", r"()B");
 
   int byteValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _byteValueId, JniCallType.byteType, []).byte;
     if (deleteOriginal) {
@@ -124,6 +130,7 @@
       Jni.accessors.getMethodIDOf(_class.reference, r"shortValue", r"()S");
 
   int shortValue({bool deleteOriginal = false}) {
+    ensureNotNull();
     final ret = Jni.accessors.callMethodWithArgs(
         reference, _shortValueId, JniCallType.shortType, []).short;
     if (deleteOriginal) {
diff --git a/pkgs/jni/lib/src/lang/jstring.dart b/pkgs/jni/lib/src/lang/jstring.dart
index fff169c..5bfcce5 100644
--- a/pkgs/jni/lib/src/lang/jstring.dart
+++ b/pkgs/jni/lib/src/lang/jstring.dart
@@ -5,11 +5,10 @@
 import 'dart:ffi';
 
 import 'package:ffi/ffi.dart';
+import 'package:jni/src/jreference.dart';
 
-import '../jexceptions.dart';
 import '../jni.dart';
 import '../jobject.dart';
-import '../jreference.dart';
 import '../third_party/generated_bindings.dart';
 import '../types.dart';
 
@@ -68,10 +67,7 @@
   /// If [deleteOriginal] is true, the underlying reference is deleted
   /// after conversion and this object will be marked as deleted.
   String toDartString({bool deleteOriginal = false}) {
-    ensureNotDeleted();
-    if (reference == nullptr) {
-      throw NullJStringException();
-    }
+    ensureNotNull();
     final length = Jni.env.GetStringLength(reference);
     final chars = Jni.env.GetStringChars(reference, nullptr);
     final result = chars.cast<Utf16>().toDartString(length: length);
diff --git a/pkgs/jni/pubspec.yaml b/pkgs/jni/pubspec.yaml
index d4a8da9..2808b3c 100644
--- a/pkgs/jni/pubspec.yaml
+++ b/pkgs/jni/pubspec.yaml
@@ -8,7 +8,7 @@
 repository: https://github.com/dart-lang/jnigen/tree/main/jni
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
   flutter: '>=2.11.0'
 
 dependencies:
diff --git a/pkgs/jnigen/android_test_runner/pubspec.yaml b/pkgs/jnigen/android_test_runner/pubspec.yaml
index fccc86e..87e4795 100644
--- a/pkgs/jnigen/android_test_runner/pubspec.yaml
+++ b/pkgs/jnigen/android_test_runner/pubspec.yaml
@@ -19,7 +19,7 @@
 version: 1.0.0+1
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 # Dependencies specify other packages that your package needs in order to work.
 # To automatically upgrade your package dependencies to the latest versions
diff --git a/pkgs/jnigen/example/in_app_java/pubspec.yaml b/pkgs/jnigen/example/in_app_java/pubspec.yaml
index 2d97acf..f99aa5d 100644
--- a/pkgs/jnigen/example/in_app_java/pubspec.yaml
+++ b/pkgs/jnigen/example/in_app_java/pubspec.yaml
@@ -8,7 +8,7 @@
 version: 1.0.0+1
 
 environment:
-  sdk: ">=3.1.0 <4.0.0"
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 dependencies:
   flutter:
diff --git a/pkgs/jnigen/example/kotlin_plugin/example/pubspec.yaml b/pkgs/jnigen/example/kotlin_plugin/example/pubspec.yaml
index 0f6224e..53ef1e3 100644
--- a/pkgs/jnigen/example/kotlin_plugin/example/pubspec.yaml
+++ b/pkgs/jnigen/example/kotlin_plugin/example/pubspec.yaml
@@ -6,7 +6,7 @@
 version: 1.0.0+1
 
 environment:
-  sdk: ">=3.1.0 <4.0.0"
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 dependencies:
   flutter:
diff --git a/pkgs/jnigen/example/kotlin_plugin/pubspec.yaml b/pkgs/jnigen/example/kotlin_plugin/pubspec.yaml
index fd89ad6..4396ff5 100644
--- a/pkgs/jnigen/example/kotlin_plugin/pubspec.yaml
+++ b/pkgs/jnigen/example/kotlin_plugin/pubspec.yaml
@@ -8,7 +8,7 @@
 publish_to: none
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
   flutter: ">=1.17.0"
 
 dependencies:
diff --git a/pkgs/jnigen/example/notification_plugin/example/pubspec.yaml b/pkgs/jnigen/example/notification_plugin/example/pubspec.yaml
index 35f3357..10478f0 100644
--- a/pkgs/jnigen/example/notification_plugin/example/pubspec.yaml
+++ b/pkgs/jnigen/example/notification_plugin/example/pubspec.yaml
@@ -20,7 +20,7 @@
 version: 1.0.0+1
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 dependencies:
   flutter:
diff --git a/pkgs/jnigen/example/notification_plugin/pubspec.yaml b/pkgs/jnigen/example/notification_plugin/pubspec.yaml
index 1f6cf49..a0e0a6a 100644
--- a/pkgs/jnigen/example/notification_plugin/pubspec.yaml
+++ b/pkgs/jnigen/example/notification_plugin/pubspec.yaml
@@ -5,7 +5,7 @@
 homepage: https://github.com/dart-lang/jnigen
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
   flutter: ">=2.11.0"
 
 dependencies:
diff --git a/pkgs/jnigen/example/pdfbox_plugin/dart_example/pubspec.yaml b/pkgs/jnigen/example/pdfbox_plugin/dart_example/pubspec.yaml
index 4af3cf1..8b8a4ef 100644
--- a/pkgs/jnigen/example/pdfbox_plugin/dart_example/pubspec.yaml
+++ b/pkgs/jnigen/example/pdfbox_plugin/dart_example/pubspec.yaml
@@ -5,7 +5,7 @@
 # homepage: https://www.example.com
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 dependencies:
   path: ^1.8.0
diff --git a/pkgs/jnigen/example/pdfbox_plugin/example/pubspec.yaml b/pkgs/jnigen/example/pdfbox_plugin/example/pubspec.yaml
index af0ea2d..47993e6 100644
--- a/pkgs/jnigen/example/pdfbox_plugin/example/pubspec.yaml
+++ b/pkgs/jnigen/example/pdfbox_plugin/example/pubspec.yaml
@@ -18,7 +18,7 @@
 version: 1.0.0+1
 
 environment:
-  sdk: ">=3.1.0 <4.0.0"
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 # Dependencies specify other packages that your package needs in order to work.
 # To automatically upgrade your package dependencies to the latest versions
diff --git a/pkgs/jnigen/example/pdfbox_plugin/pubspec.yaml b/pkgs/jnigen/example/pdfbox_plugin/pubspec.yaml
index fc9c739..c6bb920 100644
--- a/pkgs/jnigen/example/pdfbox_plugin/pubspec.yaml
+++ b/pkgs/jnigen/example/pdfbox_plugin/pubspec.yaml
@@ -6,7 +6,7 @@
 homepage: https://github.com/dart-lang/jnigen
 
 environment:
-  sdk: ">=3.1.0 <4.0.0"
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
   #flutter: ">=2.11.0"
 
 dependencies:
diff --git a/pkgs/jnigen/lib/src/bindings/dart_generator.dart b/pkgs/jnigen/lib/src/bindings/dart_generator.dart
index ab710f6..7f734ac 100644
--- a/pkgs/jnigen/lib/src/bindings/dart_generator.dart
+++ b/pkgs/jnigen/lib/src/bindings/dart_generator.dart
@@ -1703,10 +1703,10 @@
 /// garbage collect it via [NativeFinalizer] thus making it invalid.
 /// This passes the ownership to Java using [setAsDeleted].
 ///
-/// `..setAsDeleted` detaches the object from the [NativeFinalizer] and Java
+/// `toPointer` detaches the object from the [NativeFinalizer] and Java
 /// will clean up the global reference afterwards.
 ///
-/// For example `($r.toJInteger()..setAsDeleted()).reference` when the return
+/// For example `$r.toJInteger().toPointer()` when the return
 /// type is `integer`.
 class _InterfaceReturnBox extends TypeVisitor<String> {
   const _InterfaceReturnBox();
@@ -1716,8 +1716,7 @@
     // Casting is done to create a new global reference. The user might
     // use the original reference elsewhere and so the original object
     // should not be [setAsDeleted].
-    return '((\$r as $_jObject).castTo(const ${_jObject}Type())'
-        '..setAsDeleted()).reference';
+    return '(\$r as $_jObject).castTo(const ${_jObject}Type()).toPointer()';
   }
 
   @override
@@ -1725,6 +1724,6 @@
     if (node.name == 'void') {
       return '$_jni.nullptr';
     }
-    return '($_jni.J${node.boxedName}(\$r)..setAsDeleted()).reference';
+    return '$_jni.J${node.boxedName}(\$r).toPointer()';
   }
 }
diff --git a/pkgs/jnigen/pubspec.yaml b/pkgs/jnigen/pubspec.yaml
index 0bc6764..31019dd 100644
--- a/pkgs/jnigen/pubspec.yaml
+++ b/pkgs/jnigen/pubspec.yaml
@@ -8,7 +8,7 @@
 repository: https://github.com/dart-lang/jnigen/tree/main/jnigen
 
 environment:
-  sdk: '>=3.1.0 <4.0.0'
+  sdk: '>=3.1.0-262.3.beta <4.0.0'
 
 dependencies:
   json_annotation: ^4.8.0
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 f32e13e..cbc1b21 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
@@ -2978,17 +2978,13 @@
       final $r = _$impls[$p]!.stringCallback(
         $a[0].castTo(const jni.JStringType(), deleteOriginal: true),
       );
-      return (($r as jni.JObject).castTo(const jni.JObjectType())
-            ..setAsDeleted())
-          .reference;
+      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())
-            ..setAsDeleted())
-          .reference;
+      return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer();
     }
     if ($d == r"manyPrimitives(IZCD)J") {
       final $r = _$impls[$p]!.manyPrimitives(
@@ -3005,7 +3001,7 @@
             .castTo(const jni.JDoubleType(), deleteOriginal: true)
             .doubleValue(deleteOriginal: true),
       );
-      return (jni.JLong($r)..setAsDeleted()).reference;
+      return jni.JLong($r).toPointer();
     }
     return jni.nullptr;
   }
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 9d016f7..bfe2a16 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
@@ -2813,17 +2813,13 @@
       final $r = _$impls[$p]!.stringCallback(
         $a[0].castTo(const jni.JStringType(), deleteOriginal: true),
       );
-      return (($r as jni.JObject).castTo(const jni.JObjectType())
-            ..setAsDeleted())
-          .reference;
+      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())
-            ..setAsDeleted())
-          .reference;
+      return ($r as jni.JObject).castTo(const jni.JObjectType()).toPointer();
     }
     if ($d == r"manyPrimitives(IZCD)J") {
       final $r = _$impls[$p]!.manyPrimitives(
@@ -2840,7 +2836,7 @@
             .castTo(const jni.JDoubleType(), deleteOriginal: true)
             .doubleValue(deleteOriginal: true),
       );
-      return (jni.JLong($r)..setAsDeleted()).reference;
+      return jni.JLong($r).toPointer();
     }
     return jni.nullptr;
   }