Skip to content

Commit 108ae18

Browse files
[jni] Fix nullable JCollections (#2325)
* Publish jni and jnigen 0.14.2
1 parent ad157d1 commit 108ae18

File tree

10 files changed

+263
-23
lines changed

10 files changed

+263
-23
lines changed

pkgs/jni/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.14.2
2+
3+
- Fixed a bug where certain method of `JList`, `JSet`, and `JMap` did not work
4+
with nullable elements.
5+
- Fixed a bug in `JList.lastIndexOf`.
6+
17
## 0.14.1
28

39
- Updated `bin/setup.dart` to use Gradle instead of Maven for building Java sources. Added gradle executables

pkgs/jni/lib/src/util/jlist.dart

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -197,8 +197,8 @@ class JList<$E extends JObject?> extends JObject with ListMixin<$E> {
197197
_class.instanceMethodId(r'contains', r'(Ljava/lang/Object;)Z');
198198
@override
199199
bool contains(Object? element) {
200-
if (element is! JObject) return false;
201-
final elementRef = element.reference;
200+
if (element is! JObject?) return false;
201+
final elementRef = element?.reference ?? jNullReference;
202202
return _containsId(this, const jbooleanType(), [elementRef.pointer])!;
203203
}
204204

@@ -215,9 +215,9 @@ class JList<$E extends JObject?> extends JObject with ListMixin<$E> {
215215
_class.instanceMethodId(r'indexOf', r'(Ljava/lang/Object;)I');
216216
@override
217217
int indexOf(Object? element, [int start = 0]) {
218-
if (element is! JObject) return -1;
218+
if (element is! JObject?) return -1;
219219
if (start < 0) start = 0;
220-
final elementRef = element.reference;
220+
final elementRef = element?.reference ?? jNullReference;
221221
if (start == 0) {
222222
return _indexOfId(this, const jintType(), [elementRef.pointer])!;
223223
}
@@ -270,13 +270,13 @@ class JList<$E extends JObject?> extends JObject with ListMixin<$E> {
270270
_class.instanceMethodId(r'lastIndexOf', r'(Ljava/lang/Object;)I');
271271
@override
272272
int lastIndexOf(Object? element, [int? start]) {
273-
if (element is! JObject) return -1;
273+
if (element is! JObject?) return -1;
274274
if (start == null || start >= this.length) start = this.length - 1;
275-
final elementRef = element.reference;
275+
final elementRef = element?.reference ?? jNullReference;
276276
if (start == this.length - 1) {
277277
return _lastIndexOfId(this, const jintType(), [elementRef.pointer]);
278278
}
279-
final range = getRange(start, length);
279+
final range = getRange(0, start);
280280
final res = _lastIndexOfId(
281281
range,
282282
const jintType(),
@@ -290,8 +290,8 @@ class JList<$E extends JObject?> extends JObject with ListMixin<$E> {
290290
_class.instanceMethodId(r'remove', r'(Ljava/lang/Object;)Z');
291291
@override
292292
bool remove(Object? element) {
293-
if (element is! JObject) return false;
294-
final elementRef = element.reference;
293+
if (element is! JObject?) return false;
294+
final elementRef = element?.reference ?? jNullReference;
295295
return _removeId(this, const jbooleanType(), [elementRef.pointer]);
296296
}
297297

pkgs/jni/lib/src/util/jmap.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,10 @@ class JMap<$K extends JObject?, $V extends JObject?> extends JObject
154154
r'get', r'(Ljava/lang/Object;)Ljava/lang/Object;');
155155
@override
156156
$V? operator [](Object? key) {
157-
if (key is! JObject) {
157+
if (key is! JObject?) {
158158
return null;
159159
}
160-
final keyRef = key.reference;
160+
final keyRef = key?.reference ?? jNullReference;
161161
final value = _getId(this, V.nullableType, [keyRef.pointer]);
162162
return value;
163163
}
@@ -193,21 +193,21 @@ class JMap<$K extends JObject?, $V extends JObject?> extends JObject
193193
_class.instanceMethodId(r'containsKey', r'(Ljava/lang/Object;)Z');
194194
@override
195195
bool containsKey(Object? key) {
196-
if (key is! JObject) {
196+
if (key is! JObject?) {
197197
return false;
198198
}
199-
final keyRef = key.reference;
199+
final keyRef = key?.reference ?? jNullReference;
200200
return _containsKeyId(this, const jbooleanType(), [keyRef.pointer]);
201201
}
202202

203203
static final _containsValueId =
204204
_class.instanceMethodId(r'containsValue', r'(Ljava/lang/Object;)Z');
205205
@override
206206
bool containsValue(Object? value) {
207-
if (value is! JObject) {
207+
if (value is! JObject?) {
208208
return false;
209209
}
210-
final valueRef = value.reference;
210+
final valueRef = value?.reference ?? jNullReference;
211211
return _containsValueId(this, const jbooleanType(), [valueRef.pointer]);
212212
}
213213

@@ -231,10 +231,10 @@ class JMap<$K extends JObject?, $V extends JObject?> extends JObject
231231
r'remove', r'(Ljava/lang/Object;)Ljava/lang/Object;');
232232
@override
233233
$V? remove(Object? key) {
234-
if (key is! JObject) {
234+
if (key is! JObject?) {
235235
return null;
236236
}
237-
final keyRef = key.reference;
237+
final keyRef = key?.reference ?? jNullReference;
238238
final value = _removeId(this, V.nullableType, [keyRef.pointer]);
239239
return value;
240240
}

pkgs/jni/lib/src/util/jset.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ class JSet<$E extends JObject?> extends JObject with SetMixin<$E> {
170170

171171
@override
172172
bool contains(Object? element) {
173-
if (element is! JObject) {
173+
if (element is! JObject?) {
174174
return false;
175175
}
176-
final elementRef = element.reference;
176+
final elementRef = element?.reference ?? jNullReference;
177177
return _containsId(this, const jbooleanType(), [elementRef.pointer]);
178178
}
179179

@@ -212,7 +212,7 @@ class JSet<$E extends JObject?> extends JObject with SetMixin<$E> {
212212
_class.instanceMethodId(r'remove', r'(Ljava/lang/Object;)Z');
213213
@override
214214
bool remove(Object? value) {
215-
if (value is! $E) {
215+
if (value is! JObject?) {
216216
return false;
217217
}
218218
final valueRef = value?.reference ?? jNullReference;

pkgs/jni/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
name: jni
66
description: A library to access JNI from Dart and Flutter that acts as a support library for package:jnigen.
7-
version: 0.14.1
7+
version: 0.14.2
88
repository: https://github.com/dart-lang/native/tree/main/pkgs/jni
99
issue_tracker: https://github.com/dart-lang/native/issues?q=is%3Aissue+is%3Aopen+label%3Apackage%3Ajni
1010

pkgs/jni/test/jlist_test.dart

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ void run({required TestRunnerCallback testRunner}) {
2828
..releasedBy(arena);
2929
}
3030

31+
JList<JString?> testNullableDataList(Arena arena) {
32+
return [
33+
'1'.toJString()..releasedBy(arena),
34+
'2'.toJString()..releasedBy(arena),
35+
null,
36+
].toJList(JString.nullableType)
37+
..releasedBy(arena);
38+
}
39+
3140
testRunner('length get', () {
3241
using((arena) {
3342
final list = testDataList(arena);
@@ -57,6 +66,14 @@ void run({required TestRunnerCallback testRunner}) {
5766
expect(list[2].toDartString(releaseOriginal: true), '3');
5867
});
5968
});
69+
testRunner('nullable []', () {
70+
using((arena) {
71+
final list = testNullableDataList(arena);
72+
expect(list[0]!.toDartString(releaseOriginal: true), '1');
73+
expect(list[1]!.toDartString(releaseOriginal: true), '2');
74+
expect(list[2], isNull);
75+
});
76+
});
6077
testRunner('[]=', () {
6178
using((arena) {
6279
final list = testDataList(arena);
@@ -65,6 +82,16 @@ void run({required TestRunnerCallback testRunner}) {
6582
expect(list[0].toDartString(releaseOriginal: true), '2');
6683
});
6784
});
85+
testRunner('nullable []=', () {
86+
using((arena) {
87+
final list = testNullableDataList(arena);
88+
expect(list[0]!.toDartString(releaseOriginal: true), '1');
89+
list[0] = '2'.toJString()..releasedBy(arena);
90+
expect(list[0]!.toDartString(releaseOriginal: true), '2');
91+
list[0] = null;
92+
expect(list[0], isNull);
93+
});
94+
});
6895
testRunner('add', () {
6996
using((arena) {
7097
final list = testDataList(arena);
@@ -73,6 +100,16 @@ void run({required TestRunnerCallback testRunner}) {
73100
expect(list[3].toDartString(releaseOriginal: true), '4');
74101
});
75102
});
103+
testRunner('nullable add', () {
104+
using((arena) {
105+
final list = testNullableDataList(arena);
106+
list.add('4'.toJString()..releasedBy(arena));
107+
expect(list.length, 4);
108+
expect(list[3]!.toDartString(releaseOriginal: true), '4');
109+
list.add(null);
110+
expect(list[3]!.toDartString(releaseOriginal: true), '4');
111+
});
112+
});
76113
testRunner('addAll', () {
77114
using((arena) {
78115
final list = testDataList(arena);
@@ -102,6 +139,16 @@ void run({required TestRunnerCallback testRunner}) {
102139
expect(list.contains('4'.toJString()..releasedBy(arena)), false);
103140
});
104141
});
142+
testRunner('nullable contains', () {
143+
using((arena) {
144+
final list = testNullableDataList(arena);
145+
// ignore: collection_methods_unrelated_type
146+
expect(list.contains('1'), false);
147+
expect(list.contains('1'.toJString()..releasedBy(arena)), true);
148+
expect(list.contains('4'.toJString()..releasedBy(arena)), false);
149+
expect(list.contains(null), true);
150+
});
151+
});
105152
testRunner('getRange', () {
106153
using((arena) {
107154
final list = testDataList(arena);
@@ -121,6 +168,37 @@ void run({required TestRunnerCallback testRunner}) {
121168
expect(list.indexOf('1'.toJString()..toDartString(), -1), 0);
122169
});
123170
});
171+
testRunner('nullable indexOf', () {
172+
using((arena) {
173+
final list = testNullableDataList(arena);
174+
expect(list.indexOf(1), -1);
175+
expect(list.indexOf('1'.toJString()..toDartString()), 0);
176+
expect(list.indexOf('2'.toJString()..toDartString()), 1);
177+
expect(list.indexOf(null), 2);
178+
expect(list.indexOf('1'.toJString()..toDartString(), 1), -1);
179+
expect(list.indexOf('1'.toJString()..toDartString(), -1), 0);
180+
});
181+
});
182+
testRunner('lastIndexOf', () {
183+
using((arena) {
184+
final list = testDataList(arena);
185+
expect(list.lastIndexOf(1), -1);
186+
expect(list.lastIndexOf('1'.toJString()..toDartString()), 0);
187+
expect(list.lastIndexOf('2'.toJString()..toDartString()), 1);
188+
expect(list.lastIndexOf('3'.toJString()..toDartString()), 2);
189+
expect(list.lastIndexOf('3'.toJString()..toDartString(), 1), -1);
190+
});
191+
});
192+
testRunner('nullable lastIndexOf', () {
193+
using((arena) {
194+
final list = testNullableDataList(arena);
195+
expect(list.lastIndexOf(1), -1);
196+
expect(list.lastIndexOf('1'.toJString()..toDartString()), 0);
197+
expect(list.lastIndexOf('2'.toJString()..toDartString()), 1);
198+
expect(list.lastIndexOf(null), 2);
199+
expect(list.lastIndexOf(null, 1), -1);
200+
});
201+
});
124202
testRunner('insert', () {
125203
using((arena) {
126204
final list = testDataList(arena);
@@ -164,6 +242,17 @@ void run({required TestRunnerCallback testRunner}) {
164242
expect(list.remove(1), false);
165243
});
166244
});
245+
testRunner('nullable remove', () {
246+
using((arena) {
247+
final list = testNullableDataList(arena);
248+
expect(list.remove('3'.toJString()..releasedBy(arena)), false);
249+
expect(list.length, 3);
250+
expect(list.remove(null), true);
251+
expect(list.length, 2);
252+
// ignore: collection_methods_unrelated_type
253+
expect(list.remove(1), false);
254+
});
255+
});
167256
testRunner('removeAt', () {
168257
using((arena) {
169258
final list = testDataList(arena);

0 commit comments

Comments
 (0)