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 ?
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(); }
}