Repository: mockito/mockito
Issue: ArgumentCaptor.fromClass's return type should match a parameterized type
Labels: enhancement

`ArgumentCaptor.fromClass`'s return type should match a parameterized type.  I.e. the expression `ArgumentCaptor.fromClass(Class<S>)` should be of type `ArgumentCaptor<U>` where `S` is a subtype of `U`.   

For example:

```
ArgumentCaptor<Consumer<String>> captor = ArgumentCaptor.fromClass(Consumer.class)
```

does not type check (i.e. it is a compile time error). It should type check. 

The reasons that it is desirable for `ArgumentCaptor.fromClass` to allow expressions such as the example above to type check are:

1) `ArgumentCaptor.fromClass` is intended to be a convenience method to allow the user to construct an ArgumentCaptor without casting the returned value.

Currently, the user can devise a workaround such as: 

```
ArgumentCaptor<? extends Consumer<String>> captor 
= ArgumentCaptor.fromClass(Consumer.class)
```

This workaround is inconvenient, and so contrary to `ArgumentCaptor.fromClass` being a convenience method.

2) It is inconsistent with `@Captor`, which can be applied to a field with a paramterized type.  I.e.

```
@Captor ArgumentCaptor<Consumer<String>> captor 
```

type checks.


Issue comments:
PR #201


Pull request review comments:

Patch that resolved the issue:
diff --git a/src/org/mockito/ArgumentCaptor.java b/src/org/mockito/ArgumentCaptor.java
index 0efe061cf7..78c41c89f9 100644
--- a/src/org/mockito/ArgumentCaptor.java
+++ b/src/org/mockito/ArgumentCaptor.java
@@ -65,7 +65,7 @@ public class ArgumentCaptor<T> {
     HandyReturnValues handyReturnValues = new HandyReturnValues();
 
     private final CapturingMatcher<T> capturingMatcher = new CapturingMatcher<T>();
-    private final Class<T> clazz;
+    private final Class<? extends T> clazz;
 
     /**
      * @deprecated
@@ -87,7 +87,7 @@ public ArgumentCaptor() {
         this.clazz = null;
     }
 
-    ArgumentCaptor(Class<T> clazz) {
+    private ArgumentCaptor(Class<? extends T> clazz) {
         this.clazz = clazz;
     }
 
@@ -163,10 +163,11 @@ public List<T> getAllValues() {
      * future major release.
      *
      * @param clazz Type matching the parameter to be captured.
-     * @param <T> Type of clazz
+     * @param <S> Type of clazz
+     * @param <U> Type of object captured by the newly built ArgumentCaptor
      * @return A new ArgumentCaptor
      */
-    public static <T> ArgumentCaptor<T> forClass(Class<T> clazz) {
-        return new ArgumentCaptor<T>(clazz);
+    public static <U,S extends U> ArgumentCaptor<U> forClass(Class<S> clazz) {
+        return new ArgumentCaptor<U>(clazz);
     }
 }
\ No newline at end of file


Test patch:
diff --git a/test/org/mockitousage/matchers/CapturingArgumentsTest.java b/test/org/mockitousage/matchers/CapturingArgumentsTest.java
index 44c8d87b50..d833e681e2 100644
--- a/test/org/mockitousage/matchers/CapturingArgumentsTest.java
+++ b/test/org/mockitousage/matchers/CapturingArgumentsTest.java
@@ -14,6 +14,7 @@
 import org.mockitousage.IMethods;
 import org.mockitoutil.TestBase;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import static org.mockito.Matchers.any;
@@ -124,6 +125,18 @@ public void should_allow_assertions_on_captured_null() {
         verify(emailService).sendEmailTo(argument.capture());
         assertEquals(null, argument.getValue());
     }
+
+    @Test
+    public void should_allow_construction_of_captor_for_parameterized_type_in_a_convenient_way()  {
+        //the test passes if this expression compiles
+        ArgumentCaptor<List<Person>> argument = ArgumentCaptor.forClass(List.class);
+    }
+
+    @Test
+    public void should_allow_construction_of_captor_for_a_more_specific_type()  {
+        //the test passes if this expression compiles
+        ArgumentCaptor<List> argument = ArgumentCaptor.forClass(ArrayList.class);
+    }
     
     @Test
     public void should_allow_capturing_for_stubbing() {