0

As recommended by Sonar rule RSPEC-1452,

Generic wildcard types should not be used in return types

How can I define setter method of a property that accepts a List<? extends Item>, but getter method that returns List<Item>?

Consider the below contract of Cart interface:

interface Cart {
    public List<Item> getItems();
}

interface Item {
    public int getCost();
}

Clients of this contract do not need to know about any known implementations of Cart or Item interfaces, e.g.

void getValue(Cart cart) {
    int sum = cart.getItems().stream().mapToInt(Item::getCost).sum();
}

However, the library that implements the Cart interface obviously has to deal with concrete classes. Assume it (or its Builder) also has to expose a setItems method so that another internal class can set the entire list of items. Upper bound of Interface allows to pass a List<DefaultItem> to setItems method.

static class DefaultCart implements Cart {

    private List<Item> items;

    public void setItems(List<? extends Item> items) {
        this.items = new ArrayList<Item>(items);
    }

    @Override
    public List<Item> getItems() {
        return items;
    }
}

I am not happy with the above setItems method as it creates another copy of the list. What is a better way of dealing with this?

Somu
  • 3,593
  • 6
  • 34
  • 44

1 Answers1

0

How can I define setter method of a property that accepts a List<? extends Item>, but getter method that returns List<Item>?

You can't, because List<? extends Item> is not a subclass of List<Item>, i.e. they are not assignment compatible with each other.

For explanation, see: Is List<Dog> a subclass of List<Animal>

What you can do, is to make your class generic, so you don't use wildcard:

static class DefaultCart<E extends Item> implements Cart {

    private List<E> items;

    public void setItems(List<E> items) {
        this.items = items;
    }

    @Override
    public List<E> getItems() {
        return items;
    }
}
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • This gives a compile error: `The return type is incompatible with Cart.getItems()` – Somu Jun 22 '20 at 04:42
  • 1
    @Somu Then you either need to make `Cart` generic too, or you need to do what you're doing in the question code, since, as already explained in this answer, `List` is not assignment-compatible with `List`, so you can't otherwise call `setItems()` with a `List` and expect `getItems()` to return a `List`. – Andreas Jun 22 '20 at 07:31