Philipp
Philipp

Reputation: 4799

Generics: How to handle multiple bounded types in class hierarchy

I have a repository which returns objects implementing two interfaces

public interface MyRepository<T extends A & B> extends JpaRepository<T, Long>
  List<T> findAll();
  ...

Using Spring I inject all implementations of these into another class, but additionally specifying that the generic type should itself additionally implement a certain interface C

class X {
  @Autowired
  private List<MyRepository<? extends C> myCRepos;

Note that C is an interface which does not extend A & B, but all the concrete implementations I want injected implement all three interfaces

class MyConcreteClass implements A, B, C

So a public interface ConcreteRepo extends MyRepository<MyConcreteClass>is correctly found by Spring and injected, as expected in the List of class X.

If I now use the findAllmethod, its return type is inferred by the IDE as List<? extends C>.

Why is the return type not rather List<? extends A & B & C>?

For testing I want to mock this findAlland so return an object of the correct type, but the following already fails:

List<? extends C> someTestList = new ArrayList<>();
someTestList.add(new MyConcreteClass()); // 
// has error like
// The method add(capture#1-of ? extends C) in the type 
// List<capture#1-of ? extends C> is not applicable for the arguments (C)

How should I fix this error?

Finally, I want to mock this whole thing

Mockito.when(myRepo.findAll()).thenReturn(someTestList);

Same question, what should be the type someTestListand how to create it?

Upvotes: 1

Views: 164

Answers (2)

Philipp
Philipp

Reputation: 4799

After some more reading on generics, here's the solution. First, as noted by Philipp Wendler, the someTestList must be typed without a wildcard to be able to actually input something in it.

List<C> someTestList = new ArrayList<>();
someTestList.add(new MyConcreteClass()); // 

Additionally, in the call to Mockito, the compiler needs a hint on the return type:

Mockito.<List<? extends C>>when(myRepo.findAll()).thenReturn(someTestList);

Upvotes: 0

Philipp Wendler
Philipp Wendler

Reputation: 11433

I am not certain about the answer to your first question, but the second question has nothing to do with your complex type hierarchy. Whenever you have a List<? extends Something>, you will not be able to add something to it, because this basically declares the list as a list of "some unknown type", and Java cannot ensure that MyConcreteClass is an instance of "some unknown type". You can solve this and your third question by declaring someTestList as List<MyConcreteClass>.

Upvotes: 1

Related Questions