TransformOneToManyIterable implements CloseableIterable<O> { @Override public CloseableIterator<O> iterator() { return new CloseableIterator<O>() { private final Iterator<? extends I> inputItr = input.iterator(); private Iterator<O> nextElements; private Boolean hasNext; @Override public void close() { CloseableUtil.close(inputItr); } @Override public boolean hasNext() { if (null == hasNext) { if (inputItr.hasNext()) { final I possibleNext = inputItr.next(); if (validator.validate(possibleNext)) { final Iterable<O> nextElementsIterable = transform(possibleNext); if (null != nextElementsIterable) { nextElements = nextElementsIterable.iterator(); if (nextElements.hasNext()) { hasNext = true; } else { nextElements = null; hasNext(); } } else { hasNext(); } } else if (skipInvalid) { hasNext(); } else { handleInvalidItem(possibleNext); } } else { hasNext = false; nextElements = null; } } final boolean hasNextResult = _hasNext(); if (autoClose && !hasNextResult) { close(); } return hasNextResult; } @Override public O next() { if (!_hasNext() && !hasNext()) { throw new NoSuchElementException("Reached the end of the iterator"); } final O elementToReturn = nextElements.next(); if (!nextElements.hasNext()) { nextElements = null; hasNext = null; } return elementToReturn; } @Override public void remove() { throw new UnsupportedOperationException("Cannot call remove on a " + getIterableClass().getSimpleName() + " iterator"); } private boolean _hasNext() { return Boolean.TRUE.equals(hasNext) && null != nextElements && nextElements.hasNext(); } }; } TransformOneToManyIterable(final Iterable<? extends I> input);  TransformOneToManyIterable(final Iterable<? extends I> input, final Validator<I> validator);  TransformOneToManyIterable(final Iterable<? extends I> input, final Validator<I> validator, final boolean skipInvalid);  TransformOneToManyIterable(final Iterable<? extends I> input, final Validator<I> validator, final boolean skipInvalid, final boolean autoClose); @Override void close(); @Override CloseableIterator<O> iterator();  }
@Test public void shouldCreateIteratorThatReturnsOnlyValidStrings() { final String nullItem0 = null; final String validItem1 = "item 1"; final String invalidItem2 = "item2a,item2b"; final String validItems3A_3B = "item 3a,item 3b"; final String validItem4 = "item 4"; final Iterable<String> items = Arrays.asList(nullItem0, validItem1, invalidItem2, validItems3A_3B, validItem4); final Validator<String> validator = mock(Validator.class); final TransformOneToManyIterable iterable = new TransformOneToManyIterableImpl(items, validator, true); final Iterator<String> itr = iterable.iterator(); given(validator.validate(nullItem0)).willReturn(true); given(validator.validate(validItem1)).willReturn(true); given(validator.validate(invalidItem2)).willReturn(false); given(validator.validate(validItems3A_3B)).willReturn(true); given(validator.validate(validItem4)).willReturn(true); final List<String> output = Lists.newArrayList(itr); final List<String> expected = Arrays.asList("ITEM 1", "ITEM 3A", "ITEM 3B", "ITEM 4"); assertEquals(expected, output); }
@Test public void shouldCreateIteratorThatThrowsExceptionOnInvalidString() { final String item1 = "item 1"; final String item2 = "item 2a invalid,item 2b"; final String item3 = "item 3"; final Iterable<String> items = Arrays.asList(item1, item2, item3); final Validator<String> validator = mock(Validator.class); final TransformOneToManyIterable iterable = new TransformOneToManyIterableImpl(items, validator, false); final Iterator<String> itr = iterable.iterator(); given(validator.validate(item1)).willReturn(true); given(validator.validate(item2)).willReturn(false); given(validator.validate(item3)).willReturn(true); assertTrue(itr.hasNext()); assertEquals("ITEM 1", itr.next()); assertThrows(IllegalArgumentException.class, () -> itr.hasNext()); }
@Test public void shouldThrowExceptionIfNextCalledWhenNoNextString() { final String item1 = "item 1"; final String items2A_B = "item 2a,item 2b"; final Iterable<String> items = Arrays.asList(item1, items2A_B); final Validator<String> validator = mock(Validator.class); final TransformOneToManyIterable iterable = new TransformOneToManyIterableImpl(items, validator); final Iterator<String> itr = iterable.iterator(); given(validator.validate(item1)).willReturn(true); given(validator.validate(items2A_B)).willReturn(true); assertEquals("ITEM 1", itr.next()); assertEquals("ITEM 2A", itr.next()); assertEquals("ITEM 2B", itr.next()); assertThrows(NoSuchElementException.class, () -> itr.next()); }
@Test public void shouldThrowExceptionIfRemoveCalled() { final String item1 = "item 1"; final String item2 = "item 2"; final Iterable<String> items = Arrays.asList(item1, item2); final Validator<String> validator = mock(Validator.class); final TransformOneToManyIterable iterable = new TransformOneToManyIterableImpl(items, validator); final Iterator<String> itr = iterable.iterator(); given(validator.validate(item1)).willReturn(true); given(validator.validate(item2)).willReturn(true); assertThrows(UnsupportedOperationException.class, () -> itr.remove()); }