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<O> implements Iterator<O>, AutoCloseable {
+ private static final CloseableIterator<?> EMPTY_CLOSEABLE_ITERATOR = new CloseableIterator<Object>() {
+ @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 <T> CloseableIterator<T> emptyCloseableIterator() {
+ return (CloseableIterator<T>) EMPTY_CLOSEABLE_ITERATOR;
+ }
+
+ /**
+ * Creates a CloseableIterator from a regular {@link Iterator}.
+ *
+ * @throws IllegalArgumentException if the specified {@link Iterator} is a CloseableIterator
+ */
+ public static <T> CloseableIterator<T> from(final Iterator<T> iterator) {
+ // early fail
+ requireNonNull(iterator);
+ checkArgument(!(iterator instanceof CloseableIterator), "This method does not support creating a CloseableIterator from a CloseableIterator");
+ return new CloseableIterator<T>() {
+ @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;
protected abstract O doNext();
@Override
- public final O next() {
+ public O next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
*/
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;
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.<String>emptyList().iterator()).hasNext()).isFalse();
+ }
+
+ @Test(expected = NoSuchElementException.class)
+ public void verify_next_from_iterator_with_empty_iterator() {
+ CloseableIterator.from(Collections.<String>emptyList().iterator()).next();
+ }
+
static class SimpleCloseableIterator extends CloseableIterator {
int count = 0;
boolean isClosed = false;