Handle mismatch of number of type arguments (#3190)
Fixes #3000
Co-authored-by: Jörg von Frantzius <joerg.frantzius@aperto.com>
diff --git a/src/main/java/org/mockito/internal/configuration/injection/filter/TypeBasedCandidateFilter.java b/src/main/java/org/mockito/internal/configuration/injection/filter/TypeBasedCandidateFilter.java
index a62ee40..cf93d97 100644
--- a/src/main/java/org/mockito/internal/configuration/injection/filter/TypeBasedCandidateFilter.java
+++ b/src/main/java/org/mockito/internal/configuration/injection/filter/TypeBasedCandidateFilter.java
@@ -45,11 +45,19 @@
ParameterizedType genericMockType = (ParameterizedType) mockType;
Type[] actualTypeArguments = genericTypeToMock.getActualTypeArguments();
Type[] actualTypeArguments2 = genericMockType.getActualTypeArguments();
- // Recurse on type parameters, so we properly test whether e.g. Wildcard bounds
- // have a match
- result =
- recurseOnTypeArguments(
- injectMocksField, actualTypeArguments, actualTypeArguments2);
+ if (actualTypeArguments.length == actualTypeArguments2.length) {
+ // Recurse on type parameters, so we properly test whether e.g. Wildcard
+ // bounds have a match
+ result =
+ recurseOnTypeArguments(
+ injectMocksField,
+ actualTypeArguments,
+ actualTypeArguments2);
+ } else {
+ // the two ParameterizedTypes cannot match because they have unequal
+ // number of type arguments
+ result = false;
+ }
}
} else {
// mockType is a non-parameterized Class, i.e. a concrete class.
diff --git a/subprojects/junit-jupiter/src/test/java/org/mockitousage/GenericTypeMockTest.java b/subprojects/junit-jupiter/src/test/java/org/mockitousage/GenericTypeMockTest.java
index 1295df4..d87fd4d 100644
--- a/subprojects/junit-jupiter/src/test/java/org/mockitousage/GenericTypeMockTest.java
+++ b/subprojects/junit-jupiter/src/test/java/org/mockitousage/GenericTypeMockTest.java
@@ -10,6 +10,7 @@
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.MockitoAnnotations.*;
+import java.io.Serializable;
import java.sql.Time;
import java.util.ArrayList;
import java.util.Collection;
@@ -360,4 +361,69 @@
assertSame(innerList, spiedImpl.changes);
}
}
+
+ /* cannot define interface in nested test class RegressionArrayIndexOutOfBoundsExcepton ,
+ * because interface cannot be defined in a non-static inner class,
+ * and nested test class must be non-static in order for JUnit 5 to be able to run it */
+ public interface BaseRepository<E, I extends Serializable> {
+ E findById(I id);
+
+ E save(E entity);
+ }
+
+ /**
+ * Verify regression https://github.com/mockito/mockito/issues/3000 is fixed.
+ */
+ @Nested
+ public class RegressionArrayIndexOutOfBoundsException {
+
+ public class BaseService<E, I extends Serializable> {
+ private BaseRepository<E, I> repository;
+ }
+
+ public class OneRepository implements BaseRepository<Map<String, String>, String> {
+ public Map<String, String> findById(String id) {
+ return Map.of();
+ }
+
+ public Map<String, String> save(Map<String, String> entity) {
+ return entity;
+ }
+ }
+
+ public class TwoRepository implements BaseRepository<Map<Integer, String>, String> {
+ public Map<Integer, String> findById(String id) {
+ return Map.of();
+ }
+
+ public Map<Integer, String> save(Map<Integer, String> entity) {
+ return entity;
+ }
+ }
+
+ public class One {}
+ ;
+
+ public class Two implements Serializable {
+ private static final long serialVersionUID = 1L;
+ }
+
+ public class UnderTest extends BaseService<One, Two> {
+ private OneRepository oneRepository;
+ private TwoRepository twoRepository;
+ }
+
+ @Mock OneRepository oneRepository;
+
+ @Mock TwoRepository twoRepository;
+
+ @InjectMocks UnderTest underTest = new UnderTest();
+
+ @Test
+ public void testNoAioobe() {
+ assertNotNull(oneRepository);
+ assertNotNull(twoRepository);
+ assertNotNull(underTest);
+ }
+ }
}