Repository: mockito/mockito
Issue: Simplify the InvocationOnMock-API to get a casted argument
Labels: 1.* incompatible

The 2nd argument of  `InvocationOnMock.getArgumentAt(int,Class<T>)` can be removed cause it is not neccessary.

Intuitively on would write this to get a "auto casted" argument:
`String text = invocation.getArgumentAt(1,String.class)`

The type can be ommited without side effects (the implementation of InvocationOnMock discards it anyway).
`String text = invocation.getArgumentAt(1,null)`

Therefore Mockito 2.0 should consider to simplify the API and ommit the `Class`-argument here. Maybe it is also a good chance to simplify the method name too. What about  `getArgument(int index)` ?

This is how the 'new' API could look like:
`String text = invocation.getArgument(1)`


Issue comments:
I would like to mention that sometimes class argument can be useful.

In my case I would like to catch object passed to mock and write to mongo database.
The code I would like to have is:

```
// test setup
doAnswer(invocation -> mongoTemplate.insert(invocation.getArgument(0, Person.class)))
  .when(mock)
  .myMethod(any());

// test execution 
mock.myMethod(new Person("Joe", "Doe"))
```
The reason of problem is that `MongoTemplate` has 2 similar methods:
```
public <T> ExecutableInsert<T> insert(Class<T> domainType) {...) //(1)
public void insert(Object objectToSave) {..) //(2)
```
AFAIU, when I setup `doAnswer(invocation -> mongoTemplate.insert(invocation.getArgument(0))`, type inference will choose method (1) and finally I get class cast exception `Person` -> `Class`

Unfortunately, code `doAnswer(invocation -> mongoTemplate.insert((Person)invocation.getArgument(0))` does not compile

To implement my test, I have to define anonymous class `Answer` so my code is long-winded - one-liner looks much better


Pull request review comments:

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java b/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java
index b0687142e3..8445e4b70b 100644
--- a/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java
+++ b/src/main/java/org/mockito/internal/creation/bytebuddy/InterceptedInvocation.java
@@ -113,9 +113,14 @@ public Object[] getArguments() {
     }
 
     @Override
-    @SuppressWarnings("unchecked")
+    @Deprecated
     public <T> T getArgumentAt(int index, Class<T> clazz) {
-        return (T) arguments[index];
+        return (T) getArgument(index);
+    }
+
+    @Override
+    public <T> T getArgument(int index) {
+        return (T)arguments[index];
     }
 
     @Override
diff --git a/src/main/java/org/mockito/internal/invocation/InvocationImpl.java b/src/main/java/org/mockito/internal/invocation/InvocationImpl.java
index dc77a57e25..b7bf096249 100644
--- a/src/main/java/org/mockito/internal/invocation/InvocationImpl.java
+++ b/src/main/java/org/mockito/internal/invocation/InvocationImpl.java
@@ -62,10 +62,17 @@ public Object[] getArguments() {
         return arguments;
     }
 
+    @Deprecated
     public <T> T getArgumentAt(int index, Class<T> clazz) {
-        return (T) arguments[index];
+        return (T) getArgument(index);
     }
 
+    public <T> T getArgument(int index) {
+        return (T)arguments[index];
+    }
+
+
+
     public boolean isVerified() {
         return verified || isIgnoredForVerification;
     }
diff --git a/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java b/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java
index a18f1b62e2..112c7dd5a9 100644
--- a/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java
+++ b/src/main/java/org/mockito/internal/invocation/InvocationMatcher.java
@@ -122,7 +122,7 @@ private void captureRegularArguments(Invocation invocation) {
         for (int position = 0; position < regularArgumentsSize(invocation); position++) {
             ArgumentMatcher m = matchers.get(position);
             if (m instanceof CapturesArguments) {
-                ((CapturesArguments) m).captureFrom(invocation.getArgumentAt(position, Object.class));
+                ((CapturesArguments) m).captureFrom(invocation.getArgument(position));
             }
         }
     }
diff --git a/src/main/java/org/mockito/internal/stubbing/answers/ReturnsArgumentAt.java b/src/main/java/org/mockito/internal/stubbing/answers/ReturnsArgumentAt.java
index 059074d254..6db6db8899 100644
--- a/src/main/java/org/mockito/internal/stubbing/answers/ReturnsArgumentAt.java
+++ b/src/main/java/org/mockito/internal/stubbing/answers/ReturnsArgumentAt.java
@@ -39,7 +39,7 @@ public ReturnsArgumentAt(int wantedArgumentPosition) {
 
     public Object answer(InvocationOnMock invocation) throws Throwable {
         validateIndexWithinInvocationRange(invocation);
-        return invocation.getArguments()[actualArgumentPosition(invocation)];
+        return invocation.getArgument(actualArgumentPosition(invocation));
     }
 
 
diff --git a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValues.java b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValues.java
index 11304afce1..4b8b9474c5 100644
--- a/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValues.java
+++ b/src/main/java/org/mockito/internal/stubbing/defaultanswers/ReturnsEmptyValues.java
@@ -72,7 +72,7 @@ public Object answer(InvocationOnMock invocation) {
             //see issue 184.
             //mocks by default should return 0 if references are the same, otherwise some other value because they are not the same. Hence we return 1 (anything but 0 is good).
             //Only for compareTo() method by the Comparable interface
-            return invocation.getMock() == invocation.getArguments()[0] ? 0 : 1;
+            return invocation.getMock() == invocation.getArgument(0) ? 0 : 1;
         }
         
         Class<?> returnType = invocation.getMethod().getReturnType();
diff --git a/src/main/java/org/mockito/invocation/InvocationOnMock.java b/src/main/java/org/mockito/invocation/InvocationOnMock.java
index 815b8a4422..95f7667c5d 100644
--- a/src/main/java/org/mockito/invocation/InvocationOnMock.java
+++ b/src/main/java/org/mockito/invocation/InvocationOnMock.java
@@ -41,9 +41,18 @@ public interface InvocationOnMock extends Serializable {
     * @param index argument position
     * @param clazz argument type
     * @return casted argument on position
+     * @deprecated  use {@link #getArgument(int)}
     */
+    @Deprecated
     <T> T getArgumentAt(int index, Class<T> clazz);
 
+    /**
+     * Returns casted argument at the given index
+     * @param index argument index
+     * @return casted argument at the given index
+     */
+    <T> T getArgument(int index);
+
 
     /**
      * calls real method


Test patch:
diff --git a/src/test/java/org/mockito/internal/AllInvocationsFinderTest.java b/src/test/java/org/mockito/internal/AllInvocationsFinderTest.java
index c5230db380..8eea369948 100644
--- a/src/test/java/org/mockito/internal/AllInvocationsFinderTest.java
+++ b/src/test/java/org/mockito/internal/AllInvocationsFinderTest.java
@@ -54,6 +54,6 @@ public void shouldNotCountDuplicatedInteractions() throws Exception {
     }
 
     private void assertArgumentEquals(Object argumentValue, Invocation invocation) {
-        assertEquals(argumentValue, invocation.getArguments()[0]);
+        assertEquals(argumentValue, invocation.getArgument(0));
     }
 }
\ No newline at end of file
diff --git a/src/test/java/org/mockito/internal/invocation/InvocationImplTest.java b/src/test/java/org/mockito/internal/invocation/InvocationImplTest.java
index 0317dea5fe..57f229fd32 100644
--- a/src/test/java/org/mockito/internal/invocation/InvocationImplTest.java
+++ b/src/test/java/org/mockito/internal/invocation/InvocationImplTest.java
@@ -156,7 +156,7 @@ public void shouldReturnCastedArgumentAt(){
             argTypes(int.class, int.class).args(1, argument).toInvocation();
 
         //when
-        int secondArgument = invocationOnInterface.getArgumentAt(1, int.class);
+        int secondArgument = invocationOnInterface.getArgument(1);
 
         //then
         assertTrue(secondArgument == argument);
diff --git a/src/test/java/org/mockitousage/PlaygroundWithDemoOfUnclonedParametersProblemTest.java b/src/test/java/org/mockitousage/PlaygroundWithDemoOfUnclonedParametersProblemTest.java
index 882d235c81..a446bda754 100644
--- a/src/test/java/org/mockitousage/PlaygroundWithDemoOfUnclonedParametersProblemTest.java
+++ b/src/test/java/org/mockitousage/PlaygroundWithDemoOfUnclonedParametersProblemTest.java
@@ -75,7 +75,7 @@ public void shouldAlterFinalLog() {
     private Answer byCheckingLogEquals(final ImportLogBean status) {
         return new Answer() {
             public Object answer(InvocationOnMock invocation) throws Throwable {
-                ImportLogBean bean = (ImportLogBean) invocation.getArguments()[0];
+                ImportLogBean bean =  invocation.getArgument(0);
                 assertEquals(status, bean);
                 return null;
             }
diff --git a/src/test/java/org/mockitousage/customization/BDDMockitoTest.java b/src/test/java/org/mockitousage/customization/BDDMockitoTest.java
index b74487ef04..b932bd0b33 100644
--- a/src/test/java/org/mockitousage/customization/BDDMockitoTest.java
+++ b/src/test/java/org/mockitousage/customization/BDDMockitoTest.java
@@ -68,7 +68,7 @@ public void should_stub_with_throwable_classes() throws Exception {
     public void should_stub_with_answer() throws Exception {
         given(mock.simpleMethod(anyString())).willAnswer(new Answer<String>() {
             public String answer(InvocationOnMock invocation) throws Throwable {
-                return (String) invocation.getArguments()[0];
+                return  invocation.getArgument(0);
             }});
 
         Assertions.assertThat(mock.simpleMethod("foo")).isEqualTo("foo");
@@ -78,7 +78,7 @@ public String answer(InvocationOnMock invocation) throws Throwable {
     public void should_stub_with_will_answer_alias() throws Exception {
         given(mock.simpleMethod(anyString())).will(new Answer<String>() {
             public String answer(InvocationOnMock invocation) throws Throwable {
-                return (String) invocation.getArguments()[0];
+                return  invocation.getArgument(0);
             }
         });
 
@@ -184,7 +184,7 @@ public void should_stub_using_do_return_style() throws Exception {
     public void should_stub_using_do_answer_style() throws Exception {
         willAnswer(new Answer<String>() {
             public String answer(InvocationOnMock invocation) throws Throwable {
-                return (String) invocation.getArguments()[0];
+                return  invocation.getArgument(0);
             }
         })
                 .given(mock).simpleMethod(anyString());
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWithCustomAnswerTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWithCustomAnswerTest.java
index 8ca965d148..10486b7971 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingWithCustomAnswerTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWithCustomAnswerTest.java
@@ -28,7 +28,7 @@ public class StubbingWithCustomAnswerTest extends TestBase {
     public void shouldAnswer() throws Exception {
         when(mock.simpleMethod(anyString())).thenAnswer(new Answer<String>() {
             public String answer(InvocationOnMock invocation) throws Throwable {
-                String arg = (String) invocation.getArguments()[0];
+                String arg =  invocation.getArgument(0);
 
                 return invocation.getMethod().getName() + "-" + arg;
             }