Repository: mockito/mockito
Issue: DEEP_STUBS tries to mock final class

```
    <dependency>
        <groupId>org.mockito</groupId>
        <artifactId>mockito-core</artifactId>
        <version>1.10.19</version>
        <scope>test</scope>
    </dependency>
```

```
$ java -version
java version "1.8.0_91"
Java(TM) SE Runtime Environment (build 1.8.0_91-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.91-b14, mixed mode)
```

```
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;

import org.junit.Test;

public class MockitoBug {
  public interface Supplier<T> {
    public T get();
  }

  public interface StringSupplier extends Supplier<String> {}

  public interface InheritedSupplier extends StringSupplier {}

  @Test
  public void deepStubs() {
    StringSupplier mock = mock(StringSupplier.class, RETURNS_DEEP_STUBS);
    String s = mock.get();
    assertNull(s);
  }

  @Test
  public void inheritedDeepStubs() {
    InheritedSupplier mock = mock(InheritedSupplier.class, RETURNS_DEEP_STUBS);
    String s = mock.get();  // ClassCastException
    assertNull(s);
  }
}
```

```
java.lang.ClassCastException: org.mockito.internal.creation.cglib.ClassImposterizer$ClassWithSuperclassToWorkAroundCglibBug$$EnhancerByMockitoWithCGLIB$$322ebf6e cannot be cast to java.lang.String
    at MockitoBug.inheritedDeepStubs(MockitoBug.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
```

I expect the behavior for `StringSupplier` and `InheritedSupplier` to be the same: return `null` for `get`. However, `InheritedSupplier` tries to return a mock `Object` for `get`.


Issue comments:
I have a hacky workaround using Guava's `TypeToken`:

```
  private static final MockUtil mockUtil = new MockUtil();

  @SuppressWarnings("unchecked")
  private static <T> T createSmartDeepMock(TypeToken<T> mockType) {
    return (T) mock(mockType.getRawType(), createSmartDeepMockAnswer(mockType));
  }

  private static Answer<?> createSmartDeepMockAnswer(TypeToken<?> mockType) {
    Map<Method, Object> mocks = new LinkedHashMap<>();

    return invocation -> {
      Method method = invocation.getMethod();
      if (mocks.containsKey(method)) {
        return mocks.get(method);
      }

      Type returnType = method.getGenericReturnType();
      TypeToken<?> resolvedReturnType = mockType.resolveType(returnType);
      Class<?> returnClass = resolvedReturnType.getRawType();

      if (!mockUtil.isTypeMockable(returnClass)) {
        return Mockito.RETURNS_DEFAULTS.answer(invocation);
      } else {
        Object mock = createSmartDeepMock(resolvedReturnType);
        mocks.put(method, mock);
        return mock;
      }
    };
  }
```


Pull request review comments:
Codecov complains about not testing this path. I don't think this line is required per https://github.com/JeffreyFalgout/mockito/blob/b4b5b0be26aaf6218cd5b8253faf03e2d116bdb8/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java#L272-L273 which handles the `instanceof` checks in `inferFrom` which is the only method that uses the `FromParameterizedTypeGenericMetadataSupport`.

This else clause is always when `clazz instanceof Class` so this Exception is not required. See above comment.

@JeffreyFalgout 
- Can this really happen? If yes more error infos would be usefule? E.g. "Unable to determine the raw type of "+type.
- just a matter of style the `else` keywords can be removed

@TimvdLippe Haha i commented about the same in just the same minute!

Done.


Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
index 50baa3c2f6..8d150ff787 100644
--- a/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
+++ b/src/main/java/org/mockito/internal/util/reflection/GenericMetadataSupport.java
@@ -62,6 +62,48 @@ public abstract class GenericMetadataSupport {
      */
     protected Map<TypeVariable, Type> contextualActualTypeParameters = new HashMap<TypeVariable, Type>();
 
+    /**
+     * Registers the type variables for the given type and all of its superclasses and superinterfaces.
+     */
+    protected void registerAllTypeVariables(Type classType) {
+        Queue<Type> typesToRegister = new LinkedList<Type>();
+        Set<Type> registeredTypes = new HashSet<Type>();
+        typesToRegister.add(classType);
+
+        while (!typesToRegister.isEmpty()) {
+            Type typeToRegister = typesToRegister.poll();
+            if (typeToRegister == null || registeredTypes.contains(typeToRegister)) {
+                continue;
+            }
+
+            registerTypeVariablesOn(typeToRegister);
+            registeredTypes.add(typeToRegister);
+
+            Class<?> rawType = extractRawTypeOf(typeToRegister);
+            typesToRegister.add(rawType.getGenericSuperclass());
+            typesToRegister.addAll(Arrays.asList(rawType.getGenericInterfaces()));
+        }
+    }
+
+    protected Class<?> extractRawTypeOf(Type type) {
+        if (type instanceof Class) {
+            return (Class<?>) type;
+        }
+        if (type instanceof ParameterizedType) {
+            return (Class<?>) ((ParameterizedType) type).getRawType();
+        }
+        if (type instanceof BoundedType) {
+            return extractRawTypeOf(((BoundedType) type).firstBound());
+        }
+        if (type instanceof TypeVariable) {
+            /*
+             * If type is a TypeVariable, then it is needed to gather data elsewhere. Usually TypeVariables are declared
+             * on the class definition, such as such as List<E>.
+             */
+            return extractRawTypeOf(contextualActualTypeParameters.get(type));
+        }
+        throw new MockitoException("Raw extraction not supported for : '" + type + "'");
+    }
 
     protected void registerTypeVariablesOn(Type classType) {
         if (!(classType instanceof ParameterizedType)) {
@@ -270,28 +312,8 @@ private static class FromClassGenericMetadataSupport extends GenericMetadataSupp
         public FromClassGenericMetadataSupport(Class<?> clazz) {
             this.clazz = clazz;
 
-            for (Class<?> currentExploredClass = clazz;
-                 currentExploredClass != null && currentExploredClass != Object.class;
-                 currentExploredClass = superClassOf(currentExploredClass)) {
-                readActualTypeParametersOnDeclaringClass(currentExploredClass);
-            }
-        }
-
-        private Class superClassOf(Class<?> currentExploredClass) {
-            Type genericSuperclass = currentExploredClass.getGenericSuperclass();
-            if (genericSuperclass instanceof ParameterizedType) {
-                Type rawType = ((ParameterizedType) genericSuperclass).getRawType();
-                return (Class<?>) rawType;
-            }
-            return (Class<?>) genericSuperclass;
-        }
-
-        private void readActualTypeParametersOnDeclaringClass(Class<?> clazz) {
             registerTypeParametersOn(clazz.getTypeParameters());
-            registerTypeVariablesOn(clazz.getGenericSuperclass());
-            for (Type genericInterface : clazz.getGenericInterfaces()) {
-                registerTypeVariablesOn(genericInterface);
-            }
+            registerAllTypeVariables(clazz);
         }
 
         @Override
@@ -321,8 +343,7 @@ public FromParameterizedTypeGenericMetadataSupport(ParameterizedType parameteriz
         }
 
         private void readActualTypeParameters() {
-            registerTypeVariablesOn(parameterizedType.getRawType());
-            registerTypeVariablesOn(parameterizedType);
+            registerAllTypeVariables(parameterizedType);
         }
 
         @Override
@@ -403,26 +424,6 @@ public Class<?> rawType() {
             return rawType;
         }
 
-        private Class<?> extractRawTypeOf(Type type) {
-            if (type instanceof Class) {
-                return (Class<?>) type;
-            }
-            if (type instanceof ParameterizedType) {
-                return (Class<?>) ((ParameterizedType) type).getRawType();
-            }
-            if (type instanceof BoundedType) {
-                return extractRawTypeOf(((BoundedType) type).firstBound());
-            }
-            if (type instanceof TypeVariable) {
-                /*
-                 * If type is a TypeVariable, then it is needed to gather data elsewhere. Usually TypeVariables are declared
-                 * on the class definition, such as such as List<E>.
-                 */
-                return extractRawTypeOf(contextualActualTypeParameters.get(type));
-            }
-            throw new MockitoException("Raw extraction not supported for : '" + type + "'");
-        }
-
         @Override
         public List<Type> extraInterfaces() {
             Type type = extractActualBoundedTypeOf(typeVariable);


Test patch:
diff --git a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
index 44066b8ced..f580b359a3 100644
--- a/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
+++ b/src/test/java/org/mockito/internal/stubbing/defaultanswers/ReturnsGenericDeepStubsTest.java
@@ -19,6 +19,8 @@
 public class ReturnsGenericDeepStubsTest {
     interface ListOfInteger extends List<Integer> {}
 
+    interface AnotherListOfInteger extends ListOfInteger {}
+
     interface GenericsNest<K extends Comparable<K> & Cloneable> extends Map<K, Set<Number>> {
         Set<Number> remove(Object key); // override with fixed ParameterizedType
         List<? super Number> returningWildcard();
@@ -93,9 +95,11 @@ public void can_still_work_with_raw_type_in_the_return_type() throws Exception {
     public void will_return_default_value_on_non_mockable_nested_generic() throws Exception {
         GenericsNest<?> genericsNest = mock(GenericsNest.class, RETURNS_DEEP_STUBS);
         ListOfInteger listOfInteger = mock(ListOfInteger.class, RETURNS_DEEP_STUBS);
+        AnotherListOfInteger anotherListOfInteger = mock(AnotherListOfInteger.class, RETURNS_DEEP_STUBS);
 
         assertThat(genericsNest.returningNonMockableNestedGeneric().keySet().iterator().next()).isNull();
         assertThat(listOfInteger.get(25)).isEqualTo(0);
+        assertThat(anotherListOfInteger.get(25)).isEqualTo(0);
     }
 
     @Test(expected = ClassCastException.class)
diff --git a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
index d068e043d5..dff0d7f3ea 100644
--- a/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
+++ b/src/test/java/org/mockito/internal/util/reflection/GenericMetadataSupportTest.java
@@ -28,6 +28,11 @@ interface UpperBoundedTypeWithInterfaces<E extends Comparable<E> & Cloneable> {
         E get();
     }
     interface ListOfNumbers extends List<Number> {}
+    interface AnotherListOfNumbers extends ListOfNumbers {}
+
+    abstract class ListOfNumbersImpl implements ListOfNumbers {}
+    abstract class AnotherListOfNumbersImpl extends ListOfNumbersImpl {}
+
     interface ListOfAnyNumbers<N extends Number & Cloneable> extends List<N> {}
 
     interface GenericsNest<K extends Comparable<K> & Cloneable> extends Map<K, Set<Number>> {
@@ -76,6 +81,13 @@ public void can_get_type_variables_from_Class() throws Exception {
         assertThat(inferFrom(StringList.class).actualTypeArguments().keySet()).isEmpty();
     }
 
+    @Test
+    public void can_resolve_type_variables_from_ancestors() throws Exception {
+        Method listGet = List.class.getMethod("get", int.class);
+        assertThat(inferFrom(AnotherListOfNumbers.class).resolveGenericReturnType(listGet).rawType()).isEqualTo(Number.class);
+        assertThat(inferFrom(AnotherListOfNumbersImpl.class).resolveGenericReturnType(listGet).rawType()).isEqualTo(Number.class);
+    }
+
     @Test
     public void can_get_type_variables_from_ParameterizedType() throws Exception {
         assertThat(inferFrom(GenericsNest.class.getGenericInterfaces()[0]).actualTypeArguments().keySet()).hasSize(2).extracting("name").contains("K", "V");