Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate getters for static final strings #825

Merged
merged 3 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading
Loading