My situation is rather simple, I have a class Parent
and a class Child
which is extending Parent
.
If I have a method getStuff that can return either an instance of Parent or of Child, I can simply do that:
public Parent getStuff(boolean p) {
return p ? new Parent() : new Child();
}
Now what if my method can return either List<Parent>
or List<Child>
? I have to do that:
public List<? extends Parent> getListOfStuff(boolean p) {
return p
? myOtherMethodThatReturnsListOfParents()
: myOtherMethodThatReturnsListOfChilds();
}
public List<Parent> myOtherMethodThatReturnsListOfParents() {
return new ArrayList<Parent>();
}
public List<Child> myOtherMethodThatReturnsListOfChilds(boolean p) {
return new ArrayList<Child>();
}
But when I do that, Sonar reports "Generic wildcard types should not be used in return types" as a critical problem.
What is the proper way of fixing it?
Thanks
EDIT: the cleanest solution I've seen is ChristianRein's solution below (rebuild the List<Child>
as a List<Parent>
, it does exactly what I want and is so obvious in insight):
public List<Parent> getListOfStuff(boolean p) {
return p
? myOtherMethodThatReturnsListOfParents()
: new ArrayList<Parent>(myOtherMethodThatReturnsListOfChilds());
}
As your class Child extends your class Parent, you can easily write
public class Parent {
public List<Parent> getListOfStuff(final boolean p) {
return p
? myOtherMethodThatReturnsListOfParents()
: new ArrayList<>(myOtherMethodThatReturnsListOfChildren());
}
private List<Child> myOtherMethodThatReturnsListOfChildren() {
return List.of(new Child());
}
private List<Parent> myOtherMethodThatReturnsListOfParents() {
return List.of(new Parent());
}
}
This way, Sonar accepts it.
In the calling method, you may use instanceof to decide if you recieved a Child or a Parent object. In JUnit5, you may use assertInstanceOf:
@Test
void parents() {
// when
final List<Parent> result = new Parent().getListOfStuff(true);
// then
assertInstanceOf(Parent.class, result.get(0));
assertInstanceOf(Child.class, result.get(0)); // fails
}
@Test
void children() {
// when
final List<Parent> result = new Parent().getListOfStuff(false);
// then
assertInstanceOf(Child.class, result.get(0));
assertInstanceOf(Parent.class, result.get(0));
}