Search code examples
javareturn-typebounded-wildcard

How to avoid (bounded) wildcard in return parameter


I have an interface with a method returning an immutable collection with a bounded wildcard.

public interface Foo {
    Set<? extends Bar> getAllBar();
}

public interface Bar {
    String getBar();
}

An abstract class implementing that interface as well as several concrete classes extending it without overriding the method:

abstract class AbstractFoo implements Foo {
    public Set<? extends Bar> getAllBar() {
        return Collections.emptySet();
    }
}

And a concrete class extending the abstract class, overriding getAllBar, narrowing the wildcard:

public class FooImpl extends AbstractFoo {
    public Set<BarImpl> getAllBar() {
        return Collections.singleton(new BarImpl());
    }
}

public class BarImpl implements Bar {
    public String getBar() {
        return "Bar";
    }

    /**
     * additional BarImpl method
     */
    public boolean isWee() {
        return true;
    }
}

The calling code would usually iterate over the returned collection's items as Bar, but some calling classes, aware of FooImpl expect a collection of BarImpl to be able to call isWee().

class Zap {
    private FooImpl foo;

    boolean hasAnyWee() {
        return foo.getAllBar().stream().anyMatch(BarImpl::isWee);
    }
}

Of course now SonarQube complains about wildcard in return type (https://jira.sonarsource.com/browse/RSPEC-1452)

But is it so wrong in my case ?

How could I possibly avoid this ?


Solution

  • Make the interface itself generic:

    public interface Foo<T extends Bar> {
        Set<T> getAllBar();
    }
    

    Now you can have

    public class EmptyFoo implements Foo<BarImpl> {
        public Set<BarImpl>() { return Collections.emptySet(); }
    }