diff --git a/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java b/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java index ce9bdec0d..8b44a85ee 100644 --- a/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java +++ b/src/main/java/org/springframework/data/redis/core/ConvertingCursor.java @@ -119,13 +119,4 @@ public class ConvertingCursor implements Cursor { public long getPosition() { return delegate.getPosition(); } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.core.Cursor#limit(long) - */ - @Override - public Cursor limit(long count) { - return new ConvertingCursor<>(delegate.limit(count), converter); - } } diff --git a/src/main/java/org/springframework/data/redis/core/Cursor.java b/src/main/java/org/springframework/data/redis/core/Cursor.java index 76b93105e..c75a7448d 100644 --- a/src/main/java/org/springframework/data/redis/core/Cursor.java +++ b/src/main/java/org/springframework/data/redis/core/Cursor.java @@ -15,19 +15,25 @@ */ package org.springframework.data.redis.core; -import org.springframework.data.redis.util.BoundedIterator; import org.springframework.data.util.CloseableIterator; /** * Cursor abstraction to scan over the keyspace or elements within a data structure using a variant of a {@code SCAN} * command. + *

+ * Using a Java 8 {@link #stream() java.util.stream.Stream} allows to apply additional + * {@link java.util.stream.Stream#filter(java.util.function.Predicate) filters} and {@link java.util.stream.Stream#limit(long) limits} to + * the underlying {@link Cursor}. + *

+ * Make sure to {@link CloseableIterator#close() close} the cursor when done as this allows implementations to clean up + * any resources they need to keep open to iterate over elements (eg. by using a try-with-resource statement). * * @author Christoph Strobl * @author Mark Paluch * @param * @since 1.4 */ -public interface Cursor extends BoundedIterator, CloseableIterator { +public interface Cursor extends CloseableIterator { /** * Get the reference cursor.
@@ -56,15 +62,4 @@ public interface Cursor extends BoundedIterator, CloseableIterator { * @return the current position of the cursor. */ long getPosition(); - - /** - * Limit the maximum number of elements to be returned from this cursor. The returned cursor object can be used to - * iterate over the remaining items and to {@link #close() release} associated resources. The returned cursor is not - * attached to the state of {@code this} cursor and this object should be no longer used. - * - * @return a new {@link Cursor} with detached iteration state. - * @since 2.5 - */ - @Override - Cursor limit(long count); } diff --git a/src/main/java/org/springframework/data/redis/core/ScanCursor.java b/src/main/java/org/springframework/data/redis/core/ScanCursor.java index bf46058b1..414945c4c 100644 --- a/src/main/java/org/springframework/data/redis/core/ScanCursor.java +++ b/src/main/java/org/springframework/data/redis/core/ScanCursor.java @@ -43,7 +43,6 @@ public abstract class ScanCursor implements Cursor { private Iterator delegate; private final ScanOptions scanOptions; private long position; - private final long limit; /** * Crates new {@link ScanCursor} with {@code id=0} and {@link ScanOptions#NONE} @@ -82,23 +81,6 @@ public abstract class ScanCursor implements Cursor { this.cursorId = cursorId; this.state = CursorState.READY; this.delegate = Collections.emptyIterator(); - this.limit = -1; - } - - /** - * Crates a new {@link ScanCursor}. - * - * @param source source cursor. - * @param limit - * @since 2.5 - */ - private ScanCursor(ScanCursor source, long limit) { - - this.scanOptions = source.scanOptions; - this.cursorId = source.cursorId; - this.state = source.state; - this.delegate = source.delegate; - this.limit = limit; } private void scan(long cursorId) { @@ -189,10 +171,6 @@ public abstract class ScanCursor implements Cursor { assertCursorIsOpen(); - if (limit != -1 && getPosition() > limit - 1) { - return false; - } - while (!delegate.hasNext() && !CursorState.FINISHED.equals(state)) { scan(cursorId); } @@ -294,54 +272,10 @@ public abstract class ScanCursor implements Cursor { return position; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.core.Cursor#limit(long) - */ - @Override - public ScanCursor limit(long count) { - - Assert.isTrue(count >= 0, "Count must be greater or equal to zero"); - - return new ScanCursorWrapper<>(this, count); - } - /** * @author Thomas Darimont */ enum CursorState { READY, OPEN, FINISHED, CLOSED; } - - /** - * Wrapper for a concrete {@link ScanCursor} forwarding {@link #doScan(long, ScanOptions)}, {@link #doClose()} and - * {@link #isClosed()}. - * - * @param - * @since 2.5 - */ - private static class ScanCursorWrapper extends ScanCursor { - - private final ScanCursor delegate; - - public ScanCursorWrapper(ScanCursor delegate, long limit) { - super(delegate, limit); - this.delegate = delegate; - } - - @Override - protected ScanIteration doScan(long cursorId, ScanOptions options) { - return delegate.doScan(cursorId, options); - } - - @Override - protected void doClose() { - delegate.close(); - } - - @Override - public boolean isClosed() { - return delegate.isClosed(); - } - } } diff --git a/src/main/java/org/springframework/data/redis/util/BoundedIterator.java b/src/main/java/org/springframework/data/redis/util/BoundedIterator.java deleted file mode 100644 index 0540befba..000000000 --- a/src/main/java/org/springframework/data/redis/util/BoundedIterator.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2021 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.redis.util; - -import java.util.Iterator; - -/** - * Extension to {@link Iterator} that can be {@link #limit(long) limited} to a maximum number of items. - * - * @author Mark Paluch - * @since 2.5 - */ -public interface BoundedIterator extends Iterator { - - /** - * Limit the maximum number of elements to return. The limit is only applied to the returned instance and not applied - * to {@code this} iterator. - * - * @param count the maximum number of elements of iterator to return. Must be greater or equal to zero. - * @return a new instance of {@link BoundedIterator} with {@code count} applied. - */ - BoundedIterator limit(long count); -} diff --git a/src/test/java/org/springframework/data/redis/core/ScanCursorUnitTests.java b/src/test/java/org/springframework/data/redis/core/ScanCursorUnitTests.java index 67a9bdf62..cc876a4e1 100644 --- a/src/test/java/org/springframework/data/redis/core/ScanCursorUnitTests.java +++ b/src/test/java/org/springframework/data/redis/core/ScanCursorUnitTests.java @@ -24,9 +24,10 @@ import java.util.LinkedList; import java.util.List; import java.util.NoSuchElementException; import java.util.Queue; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; - import org.springframework.dao.InvalidDataAccessApiUsageException; /** @@ -200,25 +201,21 @@ class ScanCursorUnitTests { } @Test // GH-1575 - void limitShouldApplyLimitation() { + void streamLimitShouldApplyLimitation() { LinkedList> values = new LinkedList<>(); values.add(createIteration(1, "spring")); values.add(createIteration(2, "data")); values.add(createIteration(3, "redis")); values.add(createIteration(0)); - Cursor cursor = initCursor(values).limit(2); - List result = new ArrayList<>(); - while (cursor.hasNext()) { - result.add(cursor.next()); - } + Cursor cursor = initCursor(values); - assertThat(result).hasSize(2).contains("spring", "data"); + assertThat(cursor.stream().limit(2).collect(Collectors.toList())).hasSize(2).contains("spring", "data"); } @Test // GH-1575 - void limitShouldNotLimitOriginalCursor() { + void streamingCursorShouldForwardClose() { LinkedList> values = new LinkedList<>(); values.add(createIteration(1, "spring")); @@ -226,34 +223,14 @@ class ScanCursorUnitTests { values.add(createIteration(3, "redis")); values.add(createIteration(0)); Cursor cursor = initCursor(values); - cursor.limit(1); - - List result = new ArrayList<>(); - while (cursor.hasNext()) { - result.add(cursor.next()); - } - - assertThat(result).hasSize(3); - } - - @Test // GH-1575 - void decoratedCursorShouldForwardClose() { - - LinkedList> values = new LinkedList<>(); - values.add(createIteration(1, "spring")); - values.add(createIteration(2, "data")); - values.add(createIteration(3, "redis")); - values.add(createIteration(0)); - Cursor cursor = initCursor(values); - Cursor limited = cursor.limit(1); assertThat(cursor.isClosed()).isFalse(); - assertThat(limited.isClosed()).isFalse(); - limited.close(); + Stream stream = cursor.stream(); + stream.collect(Collectors.toList()); + stream.close(); assertThat(cursor.isClosed()).isTrue(); - assertThat(limited.isClosed()).isTrue(); } private CapturingCursorDummy initCursor(Queue> values) {