@@ -110,7 +110,8 @@ native void nativeSetParameter(long handle, int entityId, int propertyId, @Nulla
110110 private final int queryAttempts ;
111111 private static final int INITIAL_RETRY_BACK_OFF_IN_MS = 10 ;
112112
113- long handle ;
113+ // volatile so checkOpen() is more up-to-date (no need for synchronized; it's a race anyway)
114+ volatile long handle ;
114115
115116 Query (Box <T > box , long queryHandle , @ Nullable List <EagerRelation <T , ?>> eagerRelations , @ Nullable QueryFilter <T > filter ,
116117 @ Nullable Comparator <T > comparator ) {
@@ -135,7 +136,12 @@ protected void finalize() throws Throwable {
135136 }
136137
137138 /**
138- * If possible, try to close the query once you are done with it to reclaim resources immediately.
139+ * Closes this query and frees used resources.
140+ * <p>
141+ * If possible, call this always once done with this. Otherwise, will be called once this is finalized (e.g. garbage
142+ * collected).
143+ * <p>
144+ * Calling any other methods of this afterwards will throw an {@link IllegalStateException}.
139145 */
140146 public synchronized void close () {
141147 if (handle != 0 ) {
@@ -256,6 +262,7 @@ public long[] findIds() {
256262 */
257263 @ Nonnull
258264 public long [] findIds (final long offset , final long limit ) {
265+ checkOpen ();
259266 return box .internalCallWithReaderHandle (cursorHandle -> nativeFindIds (handle , cursorHandle , offset , limit ));
260267 }
261268
@@ -294,6 +301,7 @@ public PropertyQuery property(Property<T> property) {
294301 }
295302
296303 <R > R callInReadTx (Callable <R > callable ) {
304+ checkOpen ();
297305 return store .callInReadTxWithRetry (callable , queryAttempts , INITIAL_RETRY_BACK_OFF_IN_MS , true );
298306 }
299307
@@ -308,6 +316,7 @@ <R> R callInReadTx(Callable<R> callable) {
308316 */
309317 public void forEach (final QueryConsumer <T > consumer ) {
310318 ensureNoComparator ();
319+ checkOpen (); // findIds also checks, but throw early outside of transaction.
311320 box .getStore ().runInReadTx (() -> {
312321 LazyList <T > lazyList = new LazyList <>(box , findIds (), false );
313322 int size = lazyList .size ();
@@ -384,6 +393,7 @@ void resolveEagerRelation(@Nonnull T entity, EagerRelation<T, ?> eagerRelation)
384393
385394 /** Returns the count of Objects matching the query. */
386395 public long count () {
396+ checkOpen ();
387397 ensureNoFilter ();
388398 return box .internalCallWithReaderHandle (cursorHandle -> nativeCount (handle , cursorHandle ));
389399 }
@@ -392,6 +402,7 @@ public long count() {
392402 * Sets a parameter previously given to the {@link QueryBuilder} to a new value.
393403 */
394404 public Query <T > setParameter (Property <?> property , String value ) {
405+ checkOpen ();
395406 nativeSetParameter (handle , property .getEntityId (), property .getId (), null , value );
396407 return this ;
397408 }
@@ -402,6 +413,7 @@ public Query<T> setParameter(Property<?> property, String value) {
402413 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
403414 */
404415 public Query <T > setParameter (String alias , String value ) {
416+ checkOpen ();
405417 nativeSetParameter (handle , 0 , 0 , alias , value );
406418 return this ;
407419 }
@@ -410,6 +422,7 @@ public Query<T> setParameter(String alias, String value) {
410422 * Sets a parameter previously given to the {@link QueryBuilder} to a new value.
411423 */
412424 public Query <T > setParameter (Property <?> property , long value ) {
425+ checkOpen ();
413426 nativeSetParameter (handle , property .getEntityId (), property .getId (), null , value );
414427 return this ;
415428 }
@@ -420,6 +433,7 @@ public Query<T> setParameter(Property<?> property, long value) {
420433 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
421434 */
422435 public Query <T > setParameter (String alias , long value ) {
436+ checkOpen ();
423437 nativeSetParameter (handle , 0 , 0 , alias , value );
424438 return this ;
425439 }
@@ -428,6 +442,7 @@ public Query<T> setParameter(String alias, long value) {
428442 * Sets a parameter previously given to the {@link QueryBuilder} to a new value.
429443 */
430444 public Query <T > setParameter (Property <?> property , double value ) {
445+ checkOpen ();
431446 nativeSetParameter (handle , property .getEntityId (), property .getId (), null , value );
432447 return this ;
433448 }
@@ -438,6 +453,7 @@ public Query<T> setParameter(Property<?> property, double value) {
438453 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
439454 */
440455 public Query <T > setParameter (String alias , double value ) {
456+ checkOpen ();
441457 nativeSetParameter (handle , 0 , 0 , alias , value );
442458 return this ;
443459 }
@@ -481,6 +497,7 @@ public Query<T> setParameter(String alias, boolean value) {
481497 * Sets a parameter previously given to the {@link QueryBuilder} to new values.
482498 */
483499 public Query <T > setParameters (Property <?> property , long value1 , long value2 ) {
500+ checkOpen ();
484501 nativeSetParameters (handle , property .getEntityId (), property .getId (), null , value1 , value2 );
485502 return this ;
486503 }
@@ -491,6 +508,7 @@ public Query<T> setParameters(Property<?> property, long value1, long value2) {
491508 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
492509 */
493510 public Query <T > setParameters (String alias , long value1 , long value2 ) {
511+ checkOpen ();
494512 nativeSetParameters (handle , 0 , 0 , alias , value1 , value2 );
495513 return this ;
496514 }
@@ -499,6 +517,7 @@ public Query<T> setParameters(String alias, long value1, long value2) {
499517 * Sets a parameter previously given to the {@link QueryBuilder} to new values.
500518 */
501519 public Query <T > setParameters (Property <?> property , int [] values ) {
520+ checkOpen ();
502521 nativeSetParameters (handle , property .getEntityId (), property .getId (), null , values );
503522 return this ;
504523 }
@@ -509,6 +528,7 @@ public Query<T> setParameters(Property<?> property, int[] values) {
509528 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
510529 */
511530 public Query <T > setParameters (String alias , int [] values ) {
531+ checkOpen ();
512532 nativeSetParameters (handle , 0 , 0 , alias , values );
513533 return this ;
514534 }
@@ -517,6 +537,7 @@ public Query<T> setParameters(String alias, int[] values) {
517537 * Sets a parameter previously given to the {@link QueryBuilder} to new values.
518538 */
519539 public Query <T > setParameters (Property <?> property , long [] values ) {
540+ checkOpen ();
520541 nativeSetParameters (handle , property .getEntityId (), property .getId (), null , values );
521542 return this ;
522543 }
@@ -527,6 +548,7 @@ public Query<T> setParameters(Property<?> property, long[] values) {
527548 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
528549 */
529550 public Query <T > setParameters (String alias , long [] values ) {
551+ checkOpen ();
530552 nativeSetParameters (handle , 0 , 0 , alias , values );
531553 return this ;
532554 }
@@ -535,6 +557,7 @@ public Query<T> setParameters(String alias, long[] values) {
535557 * Sets a parameter previously given to the {@link QueryBuilder} to new values.
536558 */
537559 public Query <T > setParameters (Property <?> property , double value1 , double value2 ) {
560+ checkOpen ();
538561 nativeSetParameters (handle , property .getEntityId (), property .getId (), null , value1 , value2 );
539562 return this ;
540563 }
@@ -545,6 +568,7 @@ public Query<T> setParameters(Property<?> property, double value1, double value2
545568 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
546569 */
547570 public Query <T > setParameters (String alias , double value1 , double value2 ) {
571+ checkOpen ();
548572 nativeSetParameters (handle , 0 , 0 , alias , value1 , value2 );
549573 return this ;
550574 }
@@ -553,6 +577,7 @@ public Query<T> setParameters(String alias, double value1, double value2) {
553577 * Sets a parameter previously given to the {@link QueryBuilder} to new values.
554578 */
555579 public Query <T > setParameters (Property <?> property , String [] values ) {
580+ checkOpen ();
556581 nativeSetParameters (handle , property .getEntityId (), property .getId (), null , values );
557582 return this ;
558583 }
@@ -563,6 +588,7 @@ public Query<T> setParameters(Property<?> property, String[] values) {
563588 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
564589 */
565590 public Query <T > setParameters (String alias , String [] values ) {
591+ checkOpen ();
566592 nativeSetParameters (handle , 0 , 0 , alias , values );
567593 return this ;
568594 }
@@ -571,6 +597,7 @@ public Query<T> setParameters(String alias, String[] values) {
571597 * Sets a parameter previously given to the {@link QueryBuilder} to new values.
572598 */
573599 public Query <T > setParameters (Property <?> property , String key , String value ) {
600+ checkOpen ();
574601 nativeSetParameters (handle , property .getEntityId (), property .getId (), null , key , value );
575602 return this ;
576603 }
@@ -581,6 +608,7 @@ public Query<T> setParameters(Property<?> property, String key, String value) {
581608 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
582609 */
583610 public Query <T > setParameters (String alias , String key , String value ) {
611+ checkOpen ();
584612 nativeSetParameters (handle , 0 , 0 , alias , key , value );
585613 return this ;
586614 }
@@ -589,6 +617,7 @@ public Query<T> setParameters(String alias, String key, String value) {
589617 * Sets a parameter previously given to the {@link QueryBuilder} to new values.
590618 */
591619 public Query <T > setParameter (Property <?> property , byte [] value ) {
620+ checkOpen ();
592621 nativeSetParameter (handle , property .getEntityId (), property .getId (), null , value );
593622 return this ;
594623 }
@@ -599,6 +628,7 @@ public Query<T> setParameter(Property<?> property, byte[] value) {
599628 * @param alias as defined using {@link QueryBuilder#parameterAlias(String)}.
600629 */
601630 public Query <T > setParameter (String alias , byte [] value ) {
631+ checkOpen ();
602632 nativeSetParameter (handle , 0 , 0 , alias , value );
603633 return this ;
604634 }
@@ -609,6 +639,7 @@ public Query<T> setParameter(String alias, byte[] value) {
609639 * @return count of removed Objects
610640 */
611641 public long remove () {
642+ checkOpen ();
612643 ensureNoFilter ();
613644 return box .internalCallWithWriterHandle (cursorHandle -> nativeRemove (handle , cursorHandle ));
614645 }
@@ -632,6 +663,7 @@ public long remove() {
632663 * it may be GCed and observers may become stale (won't receive anymore data).
633664 */
634665 public SubscriptionBuilder <List <T >> subscribe () {
666+ checkOpen ();
635667 return new SubscriptionBuilder <>(publisher , null );
636668 }
637669
@@ -663,6 +695,7 @@ public void publish() {
663695 * Note: the format of the returned string may change without notice.
664696 */
665697 public String describe () {
698+ checkOpen ();
666699 return nativeToString (handle );
667700 }
668701
@@ -673,7 +706,17 @@ public String describe() {
673706 * Note: the format of the returned string may change without notice.
674707 */
675708 public String describeParameters () {
709+ checkOpen ();
676710 return nativeDescribeParameters (handle );
677711 }
678712
713+ /**
714+ * Throws if {@link #close()} has been called for this.
715+ */
716+ private void checkOpen () {
717+ if (handle == 0 ) {
718+ throw new IllegalStateException ("This query is closed. Build and use a new one." );
719+ }
720+ }
721+
679722}
0 commit comments