Skip to content

Commit 1e95809

Browse files
committed
Add override of Iterable#forEach to ensure that the cursor is always closed
JAVA-3630
1 parent 22a376e commit 1e95809

File tree

2 files changed

+31
-14
lines changed

2 files changed

+31
-14
lines changed

driver-sync/src/main/com/mongodb/client/internal/MongoIterableImpl.java

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package com.mongodb.client.internal;
1818

19-
import com.mongodb.Block;
2019
import com.mongodb.Function;
2120
import com.mongodb.ReadConcern;
2221
import com.mongodb.ReadPreference;
@@ -28,6 +27,7 @@
2827
import com.mongodb.lang.Nullable;
2928

3029
import java.util.Collection;
30+
import java.util.function.Consumer;
3131

3232
import static com.mongodb.assertions.Assertions.notNull;
3333

@@ -116,26 +116,18 @@ public <U> MongoIterable<U> map(final Function<TResult, U> mapper) {
116116
return new MappingIterable<TResult, U>(this, mapper);
117117
}
118118

119-
@SuppressWarnings("overloads")
120-
private void forEach(final Block<? super TResult> block) {
121-
MongoCursor<TResult> cursor = iterator();
122-
try {
119+
@Override
120+
public void forEach(final Consumer<? super TResult> action) {
121+
try (MongoCursor<TResult> cursor = iterator()) {
123122
while (cursor.hasNext()) {
124-
block.apply(cursor.next());
123+
action.accept(cursor.next());
125124
}
126-
} finally {
127-
cursor.close();
128125
}
129126
}
130127

131128
@Override
132129
public <A extends Collection<? super TResult>> A into(final A target) {
133-
forEach(new Block<TResult>() {
134-
@Override
135-
public void apply(final TResult t) {
136-
target.add(t);
137-
}
138-
});
130+
forEach(target::add);
139131
return target;
140132
}
141133

driver-sync/src/test/unit/com/mongodb/client/internal/FindIterableSpecification.groovy

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package com.mongodb.client.internal
1919

2020
import com.mongodb.CursorType
2121
import com.mongodb.Function
22+
import com.mongodb.MongoException
2223
import com.mongodb.MongoNamespace
2324
import com.mongodb.ReadConcern
2425
import com.mongodb.client.ClientSession
@@ -300,4 +301,28 @@ class FindIterableSpecification extends Specification {
300301
then:
301302
mongoIterable.getBatchSize() == batchSize
302303
}
304+
305+
// Really testing MongoIterableImpl#forEach, but doing it once here since that class is abstract
306+
def 'forEach should close cursor when there is an exception during iteration'() {
307+
given:
308+
def cursor = Mock(BatchCursor) {
309+
hasNext() >> {
310+
throw new MongoException('');
311+
}
312+
}
313+
def executor = new TestOperationExecutor([cursor])
314+
def mongoIterable = new FindIterableImpl(null, namespace, Document, Document, codecRegistry, readPreference, readConcern,
315+
executor, new Document())
316+
317+
when:
318+
mongoIterable.forEach(new Consumer<Document>() {
319+
@Override
320+
void accept(Document document) {
321+
}
322+
})
323+
324+
then:
325+
thrown(MongoException)
326+
1 * cursor.close()
327+
}
303328
}

0 commit comments

Comments
 (0)