Skip to content

Commit

Permalink
Generate getters for static final strings (#825)
Browse files Browse the repository at this point in the history
* Revert "[jnigen] Add `JLazyReference` and `JFinalString` (dart-archive/jnigen#400)"

This reverts commit 8456a7c.

* Close #792
  • Loading branch information
HosseinYousefi committed Nov 27, 2023
1 parent de50546 commit 0051e78
Show file tree
Hide file tree
Showing 15 changed files with 168 additions and 141 deletions.
31 changes: 0 additions & 31 deletions pkgs/jni/lib/src/jfinal_string.dart

This file was deleted.

46 changes: 2 additions & 44 deletions pkgs/jni/lib/src/jreference.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ extension ProtectedJReference on JReference {
///
/// Detaches the finalizer so the underlying pointer will not be deleted.
JObjectPtr toPointer() {
final ref = reference;
setAsReleased();
return ref;
return _reference;
}
}

Expand All @@ -43,9 +42,7 @@ abstract class JReference implements Finalizable {
NativeFinalizer(Jni.env.ptr.ref.DeleteGlobalRef.cast());

JReference.fromRef(this._reference) {
if (_reference != nullptr) {
_finalizer.attach(this, _reference, detach: this);
}
_finalizer.attach(this, _reference, detach: this);
}

bool _released = false;
Expand Down Expand Up @@ -83,45 +80,6 @@ abstract class JReference implements Finalizable {
void releasedBy(Arena arena) => arena.onReleaseAll(release);
}

/// Creates a "lazy" [JReference].
///
/// The first use of [reference] will call [lazyReference].
///
/// This is useful when the Java object is not necessarily used directly, and
/// there are alternative ways to get a Dart representation of the Object.
///
/// Object mixed in with this must call their super.[fromRef] constructor
/// with [nullptr].
///
/// Also see [JFinalString].
mixin JLazyReference on JReference {
JObjectPtr? _lazyReference;

JObjectPtr Function() get lazyReference;

@override
JObjectPtr get reference {
if (_lazyReference == null) {
_lazyReference = lazyReference();
JReference._finalizer.attach(this, _lazyReference!, detach: this);
return _lazyReference!;
}
if (_released) {
throw UseAfterReleaseError();
}
return _lazyReference!;
}

@override
void release() {
setAsReleased();
if (_lazyReference == null) {
return;
}
Jni.env.DeleteGlobalRef(_lazyReference!);
}
}

extension JReferenceUseExtension<T extends JReference> on T {
/// Applies [callback] on [this] object and then delete the underlying JNI
/// reference, returning the result of [callback].
Expand Down
43 changes: 0 additions & 43 deletions pkgs/jni/test/jfinal_string_test.dart

This file was deleted.

3 changes: 3 additions & 0 deletions pkgs/jnigen/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

- **Breaking Change**: The generated impl class for interfaces is now an
`interface`.
- **Breaking Change** ([#792](https://github.com/dart-lang/native/issues/792)]):
`static final String` fields get converted to `JString` getters instead of
`static const String` fields in Dart.

## 0.7.0

Expand Down
38 changes: 30 additions & 8 deletions pkgs/jnigen/example/in_app_java/lib/android_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -140,24 +140,35 @@ class EmojiCompat extends jni.JObject {

/// The type which includes information such as the signature of this class.
static const type = $EmojiCompatType();
static final _get_EDITOR_INFO_METAVERSION_KEY =
jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
"get_EmojiCompat__EDITOR_INFO_METAVERSION_KEY")
.asFunction<jni.JniResult Function()>();

/// from: static public final java.lang.String EDITOR_INFO_METAVERSION_KEY
/// The returned object must be released after use, by calling the [release] method.
///
/// Key in EditorInfo\#extras that represents the emoji metadata version used by the
/// widget. The existence of the value means that the widget is using EmojiCompat.
/// <p/>
/// If exists, the value for the key is an {@code int} and can be used to query EmojiCompat to
/// see whether the widget has the ability to display a certain emoji using
/// \#hasEmojiGlyph(CharSequence, int).
static const EDITOR_INFO_METAVERSION_KEY =
r"""android.support.text.emoji.emojiCompat_metadataVersion""";
static jni.JString get EDITOR_INFO_METAVERSION_KEY => const jni.JStringType()
.fromRef(_get_EDITOR_INFO_METAVERSION_KEY().object);

static final _get_EDITOR_INFO_REPLACE_ALL_KEY =
jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
"get_EmojiCompat__EDITOR_INFO_REPLACE_ALL_KEY")
.asFunction<jni.JniResult Function()>();

/// from: static public final java.lang.String EDITOR_INFO_REPLACE_ALL_KEY
/// The returned object must be released after use, by calling the [release] method.
///
/// Key in EditorInfo\#extras that represents EmojiCompat.Config\#setReplaceAll(boolean) configuration parameter. The key is added only if
/// EmojiCompat is used by the widget. If exists, the value is a boolean.
static const EDITOR_INFO_REPLACE_ALL_KEY =
r"""android.support.text.emoji.emojiCompat_replaceAll""";
static jni.JString get EDITOR_INFO_REPLACE_ALL_KEY => const jni.JStringType()
.fromRef(_get_EDITOR_INFO_REPLACE_ALL_KEY().object);

/// from: static public final int LOAD_STATE_DEFAULT
///
Expand Down Expand Up @@ -323,7 +334,6 @@ class EmojiCompat extends jni.JObject {
/// androidx.core.graphics.PaintCompat\#hasGlyph(Paint, String) for each emoji
/// subsequence.
static const EMOJI_FALLBACK = 2;

static final _init = jniLookup<
ffi
.NativeFunction<jni.JniResult Function(ffi.Pointer<ffi.Void>)>>(
Expand Down Expand Up @@ -2398,9 +2408,15 @@ class Build_Partition extends jni.JObject {

/// The type which includes information such as the signature of this class.
static const type = $Build_PartitionType();
static final _get_PARTITION_NAME_SYSTEM =
jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
"get_Build_Partition__PARTITION_NAME_SYSTEM")
.asFunction<jni.JniResult Function()>();

/// from: static public final java.lang.String PARTITION_NAME_SYSTEM
static const PARTITION_NAME_SYSTEM = r"""system""";
/// The returned object must be released after use, by calling the [release] method.
static jni.JString get PARTITION_NAME_SYSTEM =>
const jni.JStringType().fromRef(_get_PARTITION_NAME_SYSTEM().object);

static final _getName = jniLookup<
ffi
Expand Down Expand Up @@ -2754,7 +2770,6 @@ class Build_VERSION_CODES extends jni.JObject {

/// from: static public final int TIRAMISU
static const TIRAMISU = 33;

static final _new0 = jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
"Build_VERSION_CODES__new0")
.asFunction<jni.JniResult Function()>();
Expand Down Expand Up @@ -3058,8 +3073,15 @@ class Build extends jni.JObject {
static jni.JString get TYPE =>
const jni.JStringType().fromRef(_get_TYPE().object);

static final _get_UNKNOWN =
jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
"get_Build__UNKNOWN")
.asFunction<jni.JniResult Function()>();

/// from: static public final java.lang.String UNKNOWN
static const UNKNOWN = r"""unknown""";
/// The returned object must be released after use, by calling the [release] method.
static jni.JString get UNKNOWN =>
const jni.JStringType().fromRef(_get_UNKNOWN().object);

static final _get_USER =
jniLookup<ffi.NativeFunction<jni.JniResult Function()>>("get_Build__USER")
Expand Down
59 changes: 59 additions & 0 deletions pkgs/jnigen/example/in_app_java/src/android_utils/android_utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,36 @@ JniResult EmojiCompat__updateEditorInfo(jobject self_, jobject outAttrs) {
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
}

jfieldID _f_EmojiCompat__EDITOR_INFO_METAVERSION_KEY = NULL;
FFI_PLUGIN_EXPORT
JniResult get_EmojiCompat__EDITOR_INFO_METAVERSION_KEY() {
load_env();
load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
if (_c_EmojiCompat == NULL)
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
load_static_field(_c_EmojiCompat,
&_f_EmojiCompat__EDITOR_INFO_METAVERSION_KEY,
"EDITOR_INFO_METAVERSION_KEY", "Ljava/lang/String;");
jobject _result = (*jniEnv)->GetStaticObjectField(
jniEnv, _c_EmojiCompat, _f_EmojiCompat__EDITOR_INFO_METAVERSION_KEY);
return to_global_ref_result(_result);
}

jfieldID _f_EmojiCompat__EDITOR_INFO_REPLACE_ALL_KEY = NULL;
FFI_PLUGIN_EXPORT
JniResult get_EmojiCompat__EDITOR_INFO_REPLACE_ALL_KEY() {
load_env();
load_class_global_ref(&_c_EmojiCompat, "androidx/emoji2/text/EmojiCompat");
if (_c_EmojiCompat == NULL)
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
load_static_field(_c_EmojiCompat,
&_f_EmojiCompat__EDITOR_INFO_REPLACE_ALL_KEY,
"EDITOR_INFO_REPLACE_ALL_KEY", "Ljava/lang/String;");
jobject _result = (*jniEnv)->GetStaticObjectField(
jniEnv, _c_EmojiCompat, _f_EmojiCompat__EDITOR_INFO_REPLACE_ALL_KEY);
return to_global_ref_result(_result);
}

// androidx.emoji2.text.EmojiCompat$Config
jclass _c_EmojiCompat_Config = NULL;

Expand Down Expand Up @@ -1435,6 +1465,21 @@ JniResult Build_Partition__hashCode1(jobject self_) {
return (JniResult){.value = {.i = _result}, .exception = check_exception()};
}

jfieldID _f_Build_Partition__PARTITION_NAME_SYSTEM = NULL;
FFI_PLUGIN_EXPORT
JniResult get_Build_Partition__PARTITION_NAME_SYSTEM() {
load_env();
load_class_global_ref(&_c_Build_Partition, "android/os/Build$Partition");
if (_c_Build_Partition == NULL)
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
load_static_field(_c_Build_Partition,
&_f_Build_Partition__PARTITION_NAME_SYSTEM,
"PARTITION_NAME_SYSTEM", "Ljava/lang/String;");
jobject _result = (*jniEnv)->GetStaticObjectField(
jniEnv, _c_Build_Partition, _f_Build_Partition__PARTITION_NAME_SYSTEM);
return to_global_ref_result(_result);
}

// android.os.Build$VERSION
jclass _c_Build_VERSION = NULL;

Expand Down Expand Up @@ -2048,6 +2093,20 @@ JniResult get_Build__TYPE() {
return to_global_ref_result(_result);
}

jfieldID _f_Build__UNKNOWN = NULL;
FFI_PLUGIN_EXPORT
JniResult get_Build__UNKNOWN() {
load_env();
load_class_global_ref(&_c_Build, "android/os/Build");
if (_c_Build == NULL)
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
load_static_field(_c_Build, &_f_Build__UNKNOWN, "UNKNOWN",
"Ljava/lang/String;");
jobject _result =
(*jniEnv)->GetStaticObjectField(jniEnv, _c_Build, _f_Build__UNKNOWN);
return to_global_ref_result(_result);
}

jfieldID _f_Build__USER = NULL;
FFI_PLUGIN_EXPORT
JniResult get_Build__USER() {
Expand Down
5 changes: 4 additions & 1 deletion pkgs/jnigen/lib/src/bindings/c_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,10 @@ class _CFieldGenerator extends Visitor<Field, void> {

// If the field is final and default is assigned, then no need to wrap
// this field. It should then be a constant in dart code.
if (node.isStatic && node.isFinal && node.defaultValue != null) {
if (node.isStatic &&
node.isFinal &&
node.defaultValue != null &&
(node.defaultValue is num || node.defaultValue is bool)) {
return;
}

Expand Down
11 changes: 2 additions & 9 deletions pkgs/jnigen/lib/src/bindings/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1071,16 +1071,9 @@ class _FieldGenerator extends Visitor<Field, void> {
if (node.isFinal && node.isStatic && node.defaultValue != null) {
final name = node.finalName;
final value = node.defaultValue!;
// TODO(#31): Should we leave String as a normal getter instead?
if (value is String || value is num || value is bool) {
if (value is num || value is bool) {
writeDocs(node, writeReleaseInstructions: false);
s.write(' static const $name = ');
if (value is String) {
s.write('r"""$value"""');
} else {
s.write(value);
}
s.writeln(';\n');
s.writeln(' static const $name = $value;');
return;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,21 @@ JniResult JsonFactory__createJsonGenerator2(jobject self_, jobject out) {
return to_global_ref_result(_result);
}

jfieldID _f_JsonFactory__FORMAT_NAME_JSON = NULL;
FFI_PLUGIN_EXPORT
JniResult get_JsonFactory__FORMAT_NAME_JSON() {
load_env();
load_class_global_ref(&_c_JsonFactory,
"com/fasterxml/jackson/core/JsonFactory");
if (_c_JsonFactory == NULL)
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
load_static_field(_c_JsonFactory, &_f_JsonFactory__FORMAT_NAME_JSON,
"FORMAT_NAME_JSON", "Ljava/lang/String;");
jobject _result = (*jniEnv)->GetStaticObjectField(
jniEnv, _c_JsonFactory, _f_JsonFactory__FORMAT_NAME_JSON);
return to_global_ref_result(_result);
}

jfieldID _f_JsonFactory__DEFAULT_FACTORY_FEATURE_FLAGS = NULL;
FFI_PLUGIN_EXPORT
JniResult get_JsonFactory__DEFAULT_FACTORY_FEATURE_FLAGS() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,18 @@ class JsonFactory extends jni.JObject {

/// The type which includes information such as the signature of this class.
static const type = $JsonFactoryType();
static final _get_FORMAT_NAME_JSON =
jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
"get_JsonFactory__FORMAT_NAME_JSON")
.asFunction<jni.JniResult Function()>();

/// from: static public final java.lang.String FORMAT_NAME_JSON
/// The returned object must be released after use, by calling the [release] method.
///
/// Name used to identify JSON format
/// (and returned by \#getFormatName()
static const FORMAT_NAME_JSON = r"""JSON""";
static jni.JString get FORMAT_NAME_JSON =>
const jni.JStringType().fromRef(_get_FORMAT_NAME_JSON().object);

static final _get_DEFAULT_FACTORY_FEATURE_FLAGS =
jniLookup<ffi.NativeFunction<jni.JniResult Function()>>(
Expand Down

0 comments on commit 0051e78

Please sign in to comment.