Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wrap a java.util.Iterator to change the type of object being iterated

I am providing some facade classes for a third-party API and I need to wrap an iterator so that I can replace what is iterated with my own facade object.

Here's a simplified version of my facade class that wraps an API class called Item

class FacadeItem {
    Item item;
    FacadeItem(Item item) {
        this.item = item;
    }
}

The API provides an iterator of this form Iterator<Item>

I need to implement an iterator of this form Iterator<FacadeItem> that is backed by the iterator of the API.

I considered using the ForwardingIterator from the Guava library as follows:

class FacadeItemIterator<FacadeItem> extends ForwardingIterator<Item> {

    final Iterator<Item> delegate; // backing iterator

    FacadeItemIterator(Iterator<Item> delegate) {
        this.delegate = delegate;
    }

    @Override protected Iterator<Item> delegate() {
        return delegate;
    }

    @Override
    public FacadeItem next() {
        return new FacadeItem(super.next());
    }
}

but the Override of next() is not permitted by the compiler because it is expecting the returned type to be Item, not FacadeItem

like image 646
Glenn Lawrence Avatar asked May 16 '14 00:05

Glenn Lawrence


Video Answer


1 Answers

The Iterator interface isn't that big, so you could just write your own delegating iterator:

class FacadeIterator implements Iterator<FacadeItem> {
    private final Iterator<Item> delegate; // set in ctor

    @Override
    public FacadeItem next() {
        return new FacadeItem(delegate.next());
    }

    // the other two methods just delegate straight
}

and then

Iterator<FacadeItem> facadeIterator = new FacadeIterator(itemIterator);

If you're using Guava, you can use their Iterators.transform static method to make one of these for you:

Iterator<FacadeItem> facadeIterator = Iterators.transform(itemIterator,
    /* anon class of Function<Item, FacadeItem> */);

And in Java 1.8, this option becomes really easy:

Iterator<FacadeItem> facadeIterator
    = Iterators.transform(itemIterator, FacadeItem::new)
like image 56
yshavit Avatar answered Nov 09 '22 09:11

yshavit