From 6aabae46957f9e2b9c94e71792ccad380e29dc33 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Tue, 26 May 2015 09:45:29 +0200 Subject: [PATCH] SONAR-6590 add factory methods for empty CloseableIterator and from Iterator --- .../sonar/server/util/CloseableIterator.java | 66 +++++++++++++++++-- .../server/util/CloseableIteratorTest.java | 34 +++++++++- 2 files changed, 93 insertions(+), 7 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 c8244454baa..b63a332be9c 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 @@ -20,18 +20,74 @@ package org.sonar.server.util; import com.google.common.base.Throwables; - -import javax.annotation.CheckForNull; - import java.util.Iterator; import java.util.NoSuchElementException; +import javax.annotation.CheckForNull; + +import static com.google.common.base.Preconditions.checkArgument; +import static java.util.Objects.requireNonNull; public abstract class CloseableIterator implements Iterator, AutoCloseable { + private static final CloseableIterator EMPTY_CLOSEABLE_ITERATOR = new CloseableIterator() { + @Override + public boolean hasNext() { + return false; + } + + @Override + protected Object doNext() { + // never called anyway + throw new NoSuchElementException("Empty closeable Iterator has no element"); + } + + @Override + protected void doClose() throws Exception { + // do nothing + } + }; + + @SuppressWarnings("unchecked") + public static CloseableIterator emptyCloseableIterator() { + return (CloseableIterator) EMPTY_CLOSEABLE_ITERATOR; + } + + /** + * Creates a CloseableIterator from a regular {@link Iterator}. + * + * @throws IllegalArgumentException if the specified {@link Iterator} is a CloseableIterator + */ + public static CloseableIterator from(final Iterator iterator) { + // early fail + requireNonNull(iterator); + checkArgument(!(iterator instanceof CloseableIterator), "This method does not support creating a CloseableIterator from a CloseableIterator"); + return new CloseableIterator() { + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public T next() { + return iterator.next(); + } + + @Override + protected T doNext() { + throw new UnsupportedOperationException("hasNext has been override, doNext is never called"); + } + + @Override + protected void doClose() throws Exception { + // do nothing + } + }; + } + private O nextObject = null; boolean isClosed = false; @Override - public final boolean hasNext() { + public boolean hasNext() { // Optimization to not call bufferNext() when already closed if (isClosed) { return false; @@ -59,7 +115,7 @@ public abstract class CloseableIterator implements Iterator, AutoCloseable protected abstract O doNext(); @Override - public final O next() { + public O next() { if (!hasNext()) { throw new NoSuchElementException(); } 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 4cfb6efb50e..83f06bf385b 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 @@ -19,9 +19,9 @@ */ package org.sonar.server.util; -import org.junit.Test; - +import java.util.Collections; import java.util.NoSuchElementException; +import org.junit.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; @@ -111,6 +111,36 @@ public class CloseableIteratorTest { it.hasNext(); } + @Test + public void emptyIterator_has_next_is_false() { + assertThat(CloseableIterator.emptyCloseableIterator().hasNext()).isFalse(); + } + + @Test(expected = NoSuchElementException.class) + public void emptyIterator_next_throws_NoSuchElemetException() { + CloseableIterator.emptyCloseableIterator().next(); + } + + @Test(expected = NullPointerException.class) + public void from_iterator_throws_early_NPE_if_arg_is_null() { + CloseableIterator.from(null); + } + + @Test(expected = IllegalArgumentException.class) + public void from_iterator_throws_IAE_if_arg_is_a_CloseableIterator() { + CloseableIterator.from(new SimpleCloseableIterator()); + } + + @Test + public void verify_has_next_from_iterator_with_empty_iterator() { + assertThat(CloseableIterator.from(Collections.emptyList().iterator()).hasNext()).isFalse(); + } + + @Test(expected = NoSuchElementException.class) + public void verify_next_from_iterator_with_empty_iterator() { + CloseableIterator.from(Collections.emptyList().iterator()).next(); + } + static class SimpleCloseableIterator extends CloseableIterator { int count = 0; boolean isClosed = false; -- 2.39.5