0

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 ?

1 Answers1

2

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(); }
}
daniu
  • 14,137
  • 4
  • 32
  • 53
  • Indeed that would be the obvious way to go, but then I cannot do something like "AbsractFoo implements Foo" and then "FooImpl extends AbstractFoo implements Foo". It won't compile. – Pierre Maréchal Nov 24 '18 at 09:19
  • @PierreMarechal No, but you can do `AbstractFoo implements Foo`and then `FooImpl extends AbstractFoo`. – daniu Nov 24 '18 at 09:45
  • you're right, and I get your point. But how propagating type parameter throughout my class hierarchy is better than a bounded wildcard in the return type of a single method ? – Pierre Maréchal Nov 26 '18 at 10:54
  • @PierreMaréchal Well generics are intended to implement abstract behavior. If you feel it pollutes your class hierarchy, I'd say that's a bit of a code smell and you might want to rethink if your hierachy is too deep. After all, favor composition over inheritance. – daniu Nov 26 '18 at 11:47