22
22
import java .util .ArrayList ;
23
23
import java .util .List ;
24
24
import java .util .concurrent .atomic .AtomicBoolean ;
25
+ import java .util .concurrent .atomic .AtomicInteger ;
25
26
26
27
import io .objectbox .AbstractObjectBoxTest ;
27
28
28
29
29
30
import static org .junit .Assert .assertEquals ;
30
31
import static org .junit .Assert .assertFalse ;
32
+ import static org .junit .Assert .assertNotNull ;
31
33
import static org .junit .Assert .assertThrows ;
32
34
import static org .junit .Assert .assertTrue ;
33
35
@@ -49,18 +51,19 @@ public void exceptionListener_closedStore_works() {
49
51
store .setDbExceptionListener (e -> System .out .println ("This is never called" ));
50
52
}
51
53
52
- private static boolean weakRefListenerCalled = false ;
54
+ private static AtomicInteger weakRefListenerCalled = new AtomicInteger ( 0 ) ;
53
55
54
56
@ Test
55
57
public void exceptionListener_noLocalRef_works () throws InterruptedException {
58
+ weakRefListenerCalled .set (0 );
56
59
// Note: do not use lambda, it would keep a reference to this class
57
60
// and prevent garbage collection of the listener.
58
61
//noinspection Convert2Lambda
59
62
DbExceptionListener listenerNoRef = new DbExceptionListener () {
60
63
@ Override
61
64
public void onDbException (Exception e ) {
62
65
System .out .println ("Listener without strong reference is called" );
63
- weakRefListenerCalled = true ;
66
+ weakRefListenerCalled . incrementAndGet () ;
64
67
}
65
68
};
66
69
WeakReference <DbExceptionListener > weakReference = new WeakReference <>(listenerNoRef );
@@ -70,24 +73,25 @@ public void onDbException(Exception e) {
70
73
//noinspection UnusedAssignment
71
74
listenerNoRef = null ;
72
75
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" .
74
77
int triesClearWeakRef = 5 ;
75
78
while (weakReference .get () != null ) {
76
79
if (--triesClearWeakRef == 0 ) break ;
77
80
System .out .println ("Suggesting GC" );
78
81
System .gc ();
82
+ System .runFinalization ();
79
83
//noinspection BusyWait
80
84
Thread .sleep (300 );
81
85
}
82
86
assertEquals ("Failed to keep weak reference to listener" , 0 , triesClearWeakRef );
87
+ assertNotNull (weakReference .get ());
83
88
84
89
// Throw, listener should be called.
85
- weakRefListenerCalled = false ;
86
90
assertThrows (
87
91
DbException .class ,
88
92
() -> DbExceptionListenerJni .nativeThrowException (store .getNativeStore (), 0 )
89
93
);
90
- assertTrue ( weakRefListenerCalled );
94
+ assertEquals ( 1 , weakRefListenerCalled . get () );
91
95
92
96
// Remove reference from native side.
93
97
store .setDbExceptionListener (null );
@@ -98,18 +102,45 @@ public void onDbException(Exception e) {
98
102
if (--triesClearWeakRef == 0 ) break ;
99
103
System .out .println ("Suggesting GC" );
100
104
System .gc ();
105
+ System .runFinalization ();
101
106
//noinspection BusyWait
102
107
Thread .sleep (300 );
103
108
}
104
109
assertTrue ("Failed to release weak reference to listener" , triesClearWeakRef > 0 );
105
110
106
111
// Throw, listener should not be called.
107
- weakRefListenerCalled = false ;
108
112
assertThrows (
109
113
DbException .class ,
110
114
() -> DbExceptionListenerJni .nativeThrowException (store .getNativeStore (), 0 )
111
115
);
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 ());
113
144
}
114
145
115
146
@ Test
0 commit comments