@@ -220,7 +220,8 @@ public static boolean isSyncServerAvailable() {
220220
221221 private final File directory ;
222222 private final String canonicalPath ;
223- private final long handle ;
223+ /** Reference to the native store. Should probably get through {@link #getNativeStore()} instead. */
224+ private long handle ;
224225 private final Map <Class <?>, String > dbNameByClass = new HashMap <>();
225226 private final Map <Class <?>, Integer > entityTypeIdByClass = new HashMap <>();
226227 private final Map <Class <?>, EntityInfo <?>> propertiesByClass = new HashMap <>();
@@ -467,11 +468,12 @@ public static long sysProcStatusKb(String key) {
467468 * @return 0 if the size could not be determined (does not throw unless this store was already closed)
468469 */
469470 public long sizeOnDisk () {
470- checkOpen ();
471- return nativeSizeOnDisk (handle );
471+ return nativeSizeOnDisk (getNativeStore ());
472472 }
473473
474474 /**
475+ * Closes this if this is finalized.
476+ * <p>
475477 * Explicitly call {@link #close()} instead to avoid expensive finalization.
476478 */
477479 @ SuppressWarnings ("deprecation" ) // finalize()
@@ -481,8 +483,11 @@ protected void finalize() throws Throwable {
481483 super .finalize ();
482484 }
483485
486+ /**
487+ * Verifies this has not been {@link #close() closed}.
488+ */
484489 private void checkOpen () {
485- if (closed ) {
490+ if (isClosed () ) {
486491 throw new IllegalStateException ("Store is closed" );
487492 }
488493 }
@@ -533,13 +538,12 @@ <T> EntityInfo<T> getEntityInfo(Class<T> entityClass) {
533538 */
534539 @ Internal
535540 public Transaction beginTx () {
536- checkOpen ();
537541 // Because write TXs are typically not cached, initialCommitCount is not as relevant than for read TXs.
538542 int initialCommitCount = commitCount ;
539543 if (debugTxWrite ) {
540544 System .out .println ("Begin TX with commit count " + initialCommitCount );
541545 }
542- long nativeTx = nativeBeginTx (handle );
546+ long nativeTx = nativeBeginTx (getNativeStore () );
543547 if (nativeTx == 0 ) throw new DbException ("Could not create native transaction" );
544548
545549 Transaction tx = new Transaction (this , nativeTx , initialCommitCount );
@@ -555,7 +559,6 @@ public Transaction beginTx() {
555559 */
556560 @ Internal
557561 public Transaction beginReadTx () {
558- checkOpen ();
559562 // initialCommitCount should be acquired before starting the tx. In race conditions, there is a chance the
560563 // commitCount is already outdated. That's OK because it only gives a false positive for an TX being obsolete.
561564 // In contrast, a false negative would make a TX falsely not considered obsolete, and thus readers would not be
@@ -565,7 +568,7 @@ public Transaction beginReadTx() {
565568 if (debugTxRead ) {
566569 System .out .println ("Begin read TX with commit count " + initialCommitCount );
567570 }
568- long nativeTx = nativeBeginReadTx (handle );
571+ long nativeTx = nativeBeginReadTx (getNativeStore () );
569572 if (nativeTx == 0 ) throw new DbException ("Could not create native read transaction" );
570573
571574 Transaction tx = new Transaction (this , nativeTx , initialCommitCount );
@@ -575,6 +578,9 @@ public Transaction beginReadTx() {
575578 return tx ;
576579 }
577580
581+ /**
582+ * If this was {@link #close() closed}.
583+ */
578584 public boolean isClosed () {
579585 return closed ;
580586 }
@@ -584,8 +590,7 @@ public boolean isClosed() {
584590 * If true the schema is not updated and write transactions are not possible.
585591 */
586592 public boolean isReadOnly () {
587- checkOpen ();
588- return nativeIsReadOnly (handle );
593+ return nativeIsReadOnly (getNativeStore ());
589594 }
590595
591596 /**
@@ -621,7 +626,9 @@ public void close() {
621626 }
622627 if (handle != 0 ) { // failed before native handle was created?
623628 nativeDelete (handle );
624- // TODO set handle to 0 and check in native methods
629+ // The Java API has open checks, but just in case re-set the handle so any native methods will
630+ // not crash due to an invalid pointer.
631+ handle = 0 ;
625632 }
626633
627634 // When running the full unit test suite, we had 100+ threads before, hope this helps:
@@ -665,7 +672,7 @@ private void checkThreadTermination() {
665672 * Note: If false is returned, any number of files may have been deleted before the failure happened.
666673 */
667674 public boolean deleteAllFiles () {
668- if (!closed ) {
675+ if (!isClosed () ) {
669676 throw new IllegalStateException ("Store must be closed" );
670677 }
671678 return deleteAllFiles (directory );
@@ -765,8 +772,7 @@ public static boolean deleteAllFiles(@Nullable File baseDirectoryOrNull, @Nullab
765772 * </ul>
766773 */
767774 public void removeAllObjects () {
768- checkOpen ();
769- nativeDropAllData (handle );
775+ nativeDropAllData (getNativeStore ());
770776 }
771777
772778 @ Internal
@@ -1049,8 +1055,7 @@ public <R> void callInTxAsync(final Callable<R> callable, @Nullable final TxCall
10491055 * @return String that is typically logged by the application.
10501056 */
10511057 public String diagnose () {
1052- checkOpen ();
1053- return nativeDiagnose (handle );
1058+ return nativeDiagnose (getNativeStore ());
10541059 }
10551060
10561061 /**
@@ -1069,13 +1074,11 @@ public long validate(long pageLimit, boolean checkLeafLevel) {
10691074 if (pageLimit < 0 ) {
10701075 throw new IllegalArgumentException ("pageLimit must be zero or positive" );
10711076 }
1072- checkOpen ();
1073- return nativeValidate (handle , pageLimit , checkLeafLevel );
1077+ return nativeValidate (getNativeStore (), pageLimit , checkLeafLevel );
10741078 }
10751079
10761080 public int cleanStaleReadTransactions () {
1077- checkOpen ();
1078- return nativeCleanStaleReadTransactions (handle );
1081+ return nativeCleanStaleReadTransactions (getNativeStore ());
10791082 }
10801083
10811084 /**
@@ -1090,11 +1093,6 @@ public void closeThreadResources() {
10901093 // activeTx is cleaned up in finally blocks, so do not free them here
10911094 }
10921095
1093- @ Internal
1094- long internalHandle () {
1095- return handle ;
1096- }
1097-
10981096 /**
10991097 * A {@link io.objectbox.reactive.DataObserver} can be subscribed to data changes using the returned builder.
11001098 * The observer is supplied via {@link SubscriptionBuilder#observer(DataObserver)} and will be notified once a
@@ -1146,8 +1144,7 @@ public String startObjectBrowser() {
11461144 @ Nullable
11471145 public String startObjectBrowser (int port ) {
11481146 verifyObjectBrowserNotRunning ();
1149- checkOpen ();
1150- String url = nativeStartObjectBrowser (handle , null , port );
1147+ String url = nativeStartObjectBrowser (getNativeStore (), null , port );
11511148 if (url != null ) {
11521149 objectBrowserPort = port ;
11531150 }
@@ -1158,14 +1155,13 @@ public String startObjectBrowser(int port) {
11581155 @ Nullable
11591156 public String startObjectBrowser (String urlToBindTo ) {
11601157 verifyObjectBrowserNotRunning ();
1161- checkOpen ();
11621158 int port ;
11631159 try {
11641160 port = new URL (urlToBindTo ).getPort (); // Gives -1 if not available
11651161 } catch (MalformedURLException e ) {
11661162 throw new RuntimeException ("Can not start Object Browser at " + urlToBindTo , e );
11671163 }
1168- String url = nativeStartObjectBrowser (handle , urlToBindTo , 0 );
1164+ String url = nativeStartObjectBrowser (getNativeStore () , urlToBindTo , 0 );
11691165 if (url != null ) {
11701166 objectBrowserPort = port ;
11711167 }
@@ -1178,8 +1174,7 @@ public synchronized boolean stopObjectBrowser() {
11781174 throw new IllegalStateException ("ObjectBrowser has not been started before" );
11791175 }
11801176 objectBrowserPort = 0 ;
1181- checkOpen ();
1182- return nativeStopObjectBrowser (handle );
1177+ return nativeStopObjectBrowser (getNativeStore ());
11831178 }
11841179
11851180 @ Experimental
@@ -1204,8 +1199,7 @@ private void verifyObjectBrowserNotRunning() {
12041199 * This for example allows central error handling or special logging for database-related exceptions.
12051200 */
12061201 public void setDbExceptionListener (@ Nullable DbExceptionListener dbExceptionListener ) {
1207- checkOpen ();
1208- nativeSetDbExceptionListener (handle , dbExceptionListener );
1202+ nativeSetDbExceptionListener (getNativeStore (), dbExceptionListener );
12091203 }
12101204
12111205 @ Internal
@@ -1234,18 +1228,19 @@ public TxCallback<?> internalFailedReadTxAttemptCallback() {
12341228 }
12351229
12361230 void setDebugFlags (int debugFlags ) {
1237- checkOpen ();
1238- nativeSetDebugFlags (handle , debugFlags );
1231+ nativeSetDebugFlags (getNativeStore (), debugFlags );
12391232 }
12401233
12411234 long panicModeRemoveAllObjects (int entityId ) {
1242- checkOpen ();
1243- return nativePanicModeRemoveAllObjects (handle , entityId );
1235+ return nativePanicModeRemoveAllObjects (getNativeStore (), entityId );
12441236 }
12451237
12461238 /**
1247- * If you want to use the same ObjectBox store using the C API, e.g. via JNI, this gives the required pointer,
1248- * which you have to pass on to obx_store_wrap().
1239+ * Gets the reference to the native store. Can be used with the C API to use the same store, e.g. via JNI, by
1240+ * passing it on to {@code obx_store_wrap()}.
1241+ * <p>
1242+ * Throws if the store is closed.
1243+ * <p>
12491244 * The procedure is like this:<br>
12501245 * 1) you create a BoxStore on the Java side<br>
12511246 * 2) you call this method to get the native store pointer<br>
0 commit comments