]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6590 add factory methods for empty CloseableIterator and from Iterator
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Tue, 26 May 2015 07:45:29 +0000 (09:45 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Mon, 1 Jun 2015 15:08:28 +0000 (17:08 +0200)
server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java
server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java

index c8244454baada88cc526512c97b93c7d116b5704..b63a332be9c3ad1d8ad356b6e87b8f1137ec9246 100644 (file)
 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;
@@ -59,7 +115,7 @@ public abstract class CloseableIterator<O> implements Iterator<O>, AutoCloseable
   protected abstract O doNext();
 
   @Override
-  public final O next() {
+  public O next() {
     if (!hasNext()) {
       throw new NoSuchElementException();
     }
index 4cfb6efb50e19e9fa09937f91184bafb28b5504d..83f06bf385bb04e48f580c9a52063a019ab78474 100644 (file)
@@ -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.<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;