aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java6
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java28
2 files changed, 34 insertions, 0 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java b/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java
index 44903d9a0da..c8244454baa 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java
@@ -28,9 +28,14 @@ import java.util.NoSuchElementException;
public abstract class CloseableIterator<O> implements Iterator<O>, AutoCloseable {
private O nextObject = null;
+ boolean isClosed = false;
@Override
public final boolean hasNext() {
+ // Optimization to not call bufferNext() when already closed
+ if (isClosed) {
+ return false;
+ }
boolean hasNext = nextObject != null || bufferNext() != null;
if (!hasNext) {
close();
@@ -88,6 +93,7 @@ public abstract class CloseableIterator<O> implements Iterator<O>, AutoCloseable
public final void close() {
try {
doClose();
+ isClosed = true;
} catch (Exception e) {
Throwables.propagate(e);
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java
index 96913c04d7f..672ff885e02 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java
@@ -96,6 +96,21 @@ public class CloseableIteratorTest {
assertThat(it.isRemoved).isTrue();
}
+ @Test
+ public void has_next_should_not_call_do_next_when_already_closed() throws Exception {
+ DoNextShouldNotBeCalledWhenClosedIterator it = new DoNextShouldNotBeCalledWhenClosedIterator();
+
+ it.next();
+ it.next();
+ assertThat(it.hasNext()).isFalse();
+ // this call to hasNext close the stream
+ assertThat(it.hasNext()).isFalse();
+ assertThat(it.isClosed).isTrue();
+
+ // calling hasNext should not fail
+ it.hasNext();
+ }
+
static class SimpleCloseableIterator extends CloseableIterator {
int count = 0;
boolean isClosed = false;
@@ -147,4 +162,17 @@ public class CloseableIteratorTest {
isClosed = true;
}
}
+
+ static class DoNextShouldNotBeCalledWhenClosedIterator extends SimpleCloseableIterator {
+
+ @Override
+ protected Object doNext() {
+ if (!isClosed) {
+ return super.doNext();
+ } else {
+ throw new IllegalStateException("doNext should not be called when already closed");
+ }
+ }
+ }
+
}