Skip to content
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
2 changes: 2 additions & 0 deletions pkgs/jni/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
them in a for-loop or use methods such as `map` on them.

- Added nullable type classes for all Java objects.
- Fixed a problem where interfaces implemented in Dart would crash when calling
the default object methods: `equals`, `hashCode`, and `toString`.

## 0.12.2

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@

public class PortProxyBuilder implements InvocationHandler {
private static final PortCleaner cleaner = new PortCleaner();
private static final Method equals;
private static final Method hashCode;
private static final Method toString;

static {
Class<Object> object = Object.class;
try {
equals = object.getDeclaredMethod("equals", object);
hashCode = object.getDeclaredMethod("hashCode");
toString = object.getDeclaredMethod("toString");
} catch (NoSuchMethodException e) {
// Never happens.
throw new Error();
}
System.loadLibrary("dartjni");
}

Expand Down Expand Up @@ -115,6 +127,15 @@ private static native Object[] _invoke(

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.equals(equals)) {
return proxy == args[0];
}
if (method.equals(hashCode)) {
return System.identityHashCode(proxy);
}
if (method.equals(toString)) {
return proxy.getClass().getName() + '@' + Integer.toHexString(System.identityHashCode(proxy));
}
DartImplementation implementation = implementations.get(method.getDeclaringClass().getName());
String descriptor = getDescriptor(method);
boolean isBlocking = !asyncMethods.contains(descriptor);
Expand Down
51 changes: 30 additions & 21 deletions pkgs/jnigen/test/simple_package_test/runtime_test_registrant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ void _runJavaGC() {
} while (result.exitCode != 0);
}

Future<void> _waitUntil(bool Function() predicate) async {
for (var i = 0; i < 8; ++i) {
await Future<void>.delayed(Duration(milliseconds: (1 << i) * 100));
if (predicate()) {
return;
}
}
}

void registerTests(String groupName, TestRunnerCallback test) {
group(groupName, () {
test('static final fields - int', () {
Expand Down Expand Up @@ -636,14 +645,7 @@ void registerTests(String groupName, TestRunnerCallback test) {
// Running garbage collection does not work on Android. Skipping this
// test for android.
_runJavaGC();
for (var i = 0; i < 8; ++i) {
await Future<void>.delayed(Duration(milliseconds: (1 << i) * 100));
if (MyInterface.$impls.isEmpty) {
break;
}
}
// Since the interface is now deleted, the cleaner must signal to Dart
// to clean up.
await _waitUntil(() => MyInterface.$impls.isEmpty);
expect(MyInterface.$impls, isEmpty);
}
});
Expand Down Expand Up @@ -688,12 +690,7 @@ void registerTests(String groupName, TestRunnerCallback test) {
// Running garbage collection does not work on Android. Skipping this
// test for android.
_runJavaGC();
for (var i = 0; i < 8; ++i) {
await Future<void>.delayed(Duration(milliseconds: (1 << i) * 100));
if (MyInterface.$impls.isEmpty) {
break;
}
}
await _waitUntil(() => MyInterface.$impls.isEmpty);
// Since the interface is now deleted, the cleaner must signal to Dart
// to clean up.
expect(MyInterface.$impls, isEmpty);
Expand Down Expand Up @@ -741,19 +738,31 @@ void registerTests(String groupName, TestRunnerCallback test) {
// Running garbage collection does not work on Android. Skipping
// this test for android.
_runJavaGC();
for (var i = 0; i < 8; ++i) {
await Future<void>.delayed(
Duration(milliseconds: (1 << i) * 100));
if (MyInterface.$impls.isEmpty) {
break;
}
}
await _waitUntil(() => MyInterface.$impls.isEmpty);
// Since the interface is now deleted, the cleaner must signal to
// Dart to clean up.
expect(MyRunnable.$impls, isEmpty);
}
});
}
test('Object methods work', () async {
final runnable = MyRunnable.implement($MyRunnable(
run: () {},
));
expect(runnable == runnable, true);
expect(runnable != runnable, false);
expect(runnable.hashCode, runnable.hashCode);
expect(runnable.toString(), runnable.toString());
expect(MyRunnable.$impls, hasLength(1));
runnable.release();
if (!Platform.isAndroid) {
// Running garbage collection does not work on Android. Skipping
// this test for android.
_runJavaGC();
await _waitUntil(() => MyInterface.$impls.isEmpty);
expect(MyRunnable.$impls, isEmpty);
}
});
}
group('Dart exceptions are handled', () {
for (final exception in [UnimplementedError(), 'Hello!']) {
Expand Down
Loading