javajackson

Casting objects into interface that extends multiple interfaces


Jackson's objectMapper.readValues(...) returns a MappingIterator class, that implements both Closeable and Iterator:

public class MappingIterator<T> implements Iterator<T>, Closeable {...}

I'm using it to deserialize a JSONL, but I don't want my method to be tied to Jackson specific objects, so I've created an CloseableIterator instead that implements both:

public interface CloseableIterator<T> extends Iterator<T>, Closeable {...}

I want my method to return CloseableIterator, instead of directly exposing MappingIterator:

CloseableIterator<FooBar> readFooBars(...) {
    return objectMapper.readValues(...);
}

However, the compiler won't let me compile it without adding an unchecked cast, which seems unnecessary. Is there a way to cast an object into an interface that in turn extends multiple interfaces?


Solution

  • Unfortunately, it's not possible even with casting. The cast would fail at runtime because the returned type does not implement your interface, even if its methods are identical to MappingIterator's.

    A simple workaround is to return a private implementation of your interface that delegates to the Jackson iterator:

    private static class JacksonCloseableIterator<T> implements CloseableIterator<T> {
        private final MappingIterator<T> iterator;
        
        JacksonCloseableIterator(MappingIterator<T> iterator) {
            this.iterator = iterator;
        }
    
        @Override
        public boolean hasNext() {
            return iterator.hasNext();
        }
    
        @Override
        public T next() {
            return iterator.next();
        }
    
        @Override
        public void close() throws IOException {
            iterator.close();
        }
    }
    

    (If you have Guava, you can extend ForwardingIterator to reduce the boilerplate somewhat.)

    See here for an alternative approach using generics with multiple bounds.