Skip to content

Commit be20a77

Browse files
committed
ExceptionTest: add an exception listener without any refs to make sure JNI alone holds on to it (similar to exceptionListener_noLocalRef_works() but better be safe)
1 parent d1a8912 commit be20a77

File tree

1 file changed

+38
-7
lines changed

1 file changed

+38
-7
lines changed

tests/objectbox-java-test/src/test/java/io/objectbox/exception/ExceptionTest.java

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@
2222
import java.util.ArrayList;
2323
import java.util.List;
2424
import java.util.concurrent.atomic.AtomicBoolean;
25+
import java.util.concurrent.atomic.AtomicInteger;
2526

2627
import io.objectbox.AbstractObjectBoxTest;
2728

2829

2930
import static org.junit.Assert.assertEquals;
3031
import static org.junit.Assert.assertFalse;
32+
import static org.junit.Assert.assertNotNull;
3133
import static org.junit.Assert.assertThrows;
3234
import static org.junit.Assert.assertTrue;
3335

@@ -49,18 +51,19 @@ public void exceptionListener_closedStore_works() {
4951
store.setDbExceptionListener(e -> System.out.println("This is never called"));
5052
}
5153

52-
private static boolean weakRefListenerCalled = false;
54+
private static AtomicInteger weakRefListenerCalled = new AtomicInteger(0);
5355

5456
@Test
5557
public void exceptionListener_noLocalRef_works() throws InterruptedException {
58+
weakRefListenerCalled.set(0);
5659
// Note: do not use lambda, it would keep a reference to this class
5760
// and prevent garbage collection of the listener.
5861
//noinspection Convert2Lambda
5962
DbExceptionListener listenerNoRef = new DbExceptionListener() {
6063
@Override
6164
public void onDbException(Exception e) {
6265
System.out.println("Listener without strong reference is called");
63-
weakRefListenerCalled = true;
66+
weakRefListenerCalled.incrementAndGet();
6467
}
6568
};
6669
WeakReference<DbExceptionListener> weakReference = new WeakReference<>(listenerNoRef);
@@ -70,24 +73,25 @@ public void onDbException(Exception e) {
7073
//noinspection UnusedAssignment
7174
listenerNoRef = null;
7275

73-
// Try and fail to release weak reference.
76+
// Ensure weak reference is kept as JNI is holding on to listener using a "global ref".
7477
int triesClearWeakRef = 5;
7578
while (weakReference.get() != null) {
7679
if (--triesClearWeakRef == 0) break;
7780
System.out.println("Suggesting GC");
7881
System.gc();
82+
System.runFinalization();
7983
//noinspection BusyWait
8084
Thread.sleep(300);
8185
}
8286
assertEquals("Failed to keep weak reference to listener", 0, triesClearWeakRef);
87+
assertNotNull(weakReference.get());
8388

8489
// Throw, listener should be called.
85-
weakRefListenerCalled = false;
8690
assertThrows(
8791
DbException.class,
8892
() -> DbExceptionListenerJni.nativeThrowException(store.getNativeStore(), 0)
8993
);
90-
assertTrue(weakRefListenerCalled);
94+
assertEquals(1, weakRefListenerCalled.get());
9195

9296
// Remove reference from native side.
9397
store.setDbExceptionListener(null);
@@ -98,18 +102,45 @@ public void onDbException(Exception e) {
98102
if (--triesClearWeakRef == 0) break;
99103
System.out.println("Suggesting GC");
100104
System.gc();
105+
System.runFinalization();
101106
//noinspection BusyWait
102107
Thread.sleep(300);
103108
}
104109
assertTrue("Failed to release weak reference to listener", triesClearWeakRef > 0);
105110

106111
// Throw, listener should not be called.
107-
weakRefListenerCalled = false;
108112
assertThrows(
109113
DbException.class,
110114
() -> DbExceptionListenerJni.nativeThrowException(store.getNativeStore(), 0)
111115
);
112-
assertFalse(weakRefListenerCalled);
116+
assertEquals(1, weakRefListenerCalled.get());
117+
}
118+
119+
@Test
120+
public void exceptionListener_noref() throws InterruptedException {
121+
weakRefListenerCalled.set(0);
122+
123+
//noinspection Convert2Lambda
124+
store.setDbExceptionListener(new DbExceptionListener() {
125+
@Override
126+
public void onDbException(Exception e) {
127+
System.out.println("Listener without reference is called");
128+
weakRefListenerCalled.incrementAndGet();
129+
}
130+
});
131+
132+
for (int i = 0; i < 5; i++) {
133+
System.gc();
134+
System.runFinalization();
135+
Thread.sleep(100);
136+
}
137+
138+
// Throw, listener should be called.
139+
assertThrows(
140+
DbException.class,
141+
() -> DbExceptionListenerJni.nativeThrowException(store.getNativeStore(), 0)
142+
);
143+
assertEquals(1, weakRefListenerCalled.get());
113144
}
114145

115146
@Test

0 commit comments

Comments
 (0)