Repository: mockito/mockito
Issue: Mockito confuses varargs and single-param methods (regression)
Labels: enhancement

In Mockito 2.2.5 and later, when setting expectations for mocking a varargs method, using an array doesn't work:
```Java
Mockito.when(good.call(Mockito.any(String[].class))).thenReturn(1L);
```
And instead the contained type must be used:
```Java
Mockito.when(good.call(Mockito.any(String.class))).thenReturn(1L);
```
However in the face of an overload of the varargs method that takes a single argument (of the same type):
```Java
    Long call(String value);
    Long call(String... values);
```
This results in being unable to set an expectation for the varargs call.
This worked previously in Mockito 2.2.4 and earlier.

Reproducer: [mockito-bug.tar.gz](https://github.com/mockito/mockito/files/2769668/mockito-bug.tar.gz)



Issue comments:
I can fix it.
try this as workaround:
`Mockito.when(good.call((String[])Mockito.any())).thenReturn(1L);`
the problem is matches method from internal class VarArgAware in InstanceOf. It need to be override.
Hi @jjDevPL 

Thanks for tracking the version that changed the behavior ! This was done as part of #635.

For other here's the code in the archive : 

```java
interface Good {
    Long call(String... values);
}

interface Bad {
    Long call(String value);
    Long call(String... values);
}

private Good good = Mockito.mock(Good.class);
private Bad bad = Mockito.mock(Bad.class);

private String value = "abc";

// Expectation with `String[]` and call vararg method with a single-element outer-array.
// This passes in Mockito 2.2.4 and earlier
// This fails in Mockito 2.2.5 and later
@Test
public void testMockitoVarArgs1() {
    Mockito.when(good.call(Mockito.any(String[].class))).thenReturn(1L);

    Long count = good.call(new String[]{value});
    assertEquals(1, (long) count);
}

// The failure above can be fixed by changing the expectation to `String` (with the exception of the case below)
// This passes all Mockito versions
@Test
public void testMockitoVarArgs2() {
    Mockito.when(good.call(Mockito.any(String.class))).thenReturn(1L);

    Long count = good.call(new String[]{value});
    assertEquals(1, (long) count);
}

// However, with `bad` having the single-arg method, the fix doesn't work, and there is no way I can find to make
// this pass.
// This fails in all Mockito versions
@Test
public void testMockitoVarArgs3() {
    Mockito.when(bad.call(Mockito.any(String.class))).thenReturn(1L);

    Long count = bad.call(new String[]{value});
    assertEquals(1, (long) count);
}
```

Both `testMockitoVarArgs1` and `testMockitoVarArgs3` are failing.

1. Reagrding `testMockitoVarArgs1`, this is somehow expected, as it is a part of the enhancement of #635, however we probably missed to document this case. The stub should now be configured as : 

   ```java
   Mockito.when(good.call(Mockito.any(String.class))).thenReturn(1L);
   ```

   Note the `any(String.class)` not `any(String[].class)`.


2. The issue with `testMockitoVarArgs3` is that the stub is resolved to `Long call(String value)` because `any(String.class)` returns a single argument. But the production code is compiled with the vararg signature `Long call(String... values)`. Forcing the cast to `String[]` don't work as well.

   The only option is to use 

   ```java
   Mockito.when(bad.call((String[]) Mockito.anyVararg())).thenReturn(1L);
   ```

   Unfortunately this API is deprecated since 2.1.0, also the current return type do not indicate an array and thus forces the cast. Tweaking the vararg matcher signature can solve the issue

    ```java
    <T> T[] anyVararg() // enough for Java 8 as compiler infers the type
    <T> T[] vararg(Class<T> type) // for earlier javac version
   ```

   In this case deprecation of this matcher should be lifted, as it this is the only solution that allows to work with ambiguous method declarations.

-------------

@jjDevPL This doesn't happen if the API of the _type to mock_ is designed this way (which is better) : 

   ```
   Long call(String value, String..., moreValues)
   ```

I don't know if you own this API, but this could solves you issue faster than us.
well, the issue got bug label. There are work around but nevertheless it should be fixed. My changes are located in InstanceOf.java
```
protected Class getClazz() {
        return clazz;
    }
```
and under VarArgAware
```
  public boolean matches(Object actual) {
            return (actual != null) &&
                    (Primitives.isAssignableFromWrapper(actual.getClass(), getClazz())
                            || (getClazz().getComponentType() != null && getClazz().getComponentType().isAssignableFrom(actual.getClass()))
                            || getClazz().isAssignableFrom(actual.getClass()));
        }
```

small changes but it fixes Bad example. #635 was meged long time ago and I think Bad example is still bad.
I am trying to mock querydsl orderBy method:
   public api methods on com.querydsl.core.support.QueryBase

    public Q orderBy(OrderSpecifier<?>... o) 
    public Q orderBy(OrderSpecifier<?> o)

the project is on java 1.8 yet, and the workaround using deprecated Mockito api worked, but java version change will break it.
With #2835:

```java
when(good.call(any(String[].class))).thenReturn(1L);
```

...now works, matching any number of values passed to the varargs parameter. 

Where as:

```java
when(good.call(any(String.class))).thenReturn(1L);
```

... will match exactly one value passed to the varargs parameter.

Pull request review comments:
This test has been removed as `any()` now matches a single value passed to a varargs parameter. So this test fails with new impl. Fixing it requires changing:

```java
given(mock.methodWithVarargAndNonVarargVariants((String[]) any()))
                .willReturn("var arg method");
```

to

```java
given(mock.methodWithVarargAndNonVarargVariants(any(String[].class)))
                .willReturn("var arg method");
```

... which is no longer using casts... at this point this test becomes a duplicate of other tests such as:
* shouldMockVarargsInvocation_multiple_vararg_matcher()
* shouldDifferentiateNonVarargVariant()
* shouldMockVarargsInvocation_single_vararg_matcher()

Removed as it just duplicates existing tests in `VarargsTest`.
Hm, breaking `any()` sounds a bit scary. Is it possible to write code that works both before and after? E.g. is it possible to use `any(String[].class)` before this change as well? Ideally these are not mutually exclusive, so our users can prepare for the breaking change up front.
@big-andy-coates I had a question here about the `any` breakage ;)
Small question: can we keep the test as-is? Or could you please explain why we can no longer pass 2 bytes into the varargs method?
Just like `any(byte.class)`, an `ArgumentCaptor.forClass(byte.class)` will now only match a single value passed to a varargs parameter.

Users should either pass a second argument captor, if they wish to match exactly two values passed to the varargs, or use `ArgumentCaptor.forClass(byte[].class)`, if they wish to match any number of values passed to the varargs.

Tests already exist for this for `String` vs `String[]`. However, I've added tests covering these two alternatives, for primitive `byte`, to make things clear for you. See `should_capture_byte_vararg_by_creating_captor_with_primitive_2_args` and `should_capture_byte_vararg_by_creating_captor_with_primitive_array`, respectively.

Note, this is already documented in the `ArgumentCaptor.forClass() behaviour change` section in the description of this PR.  I'm guessing / assuming that we can copy the details of the breaking changes from the description into the release notes for v5.0.0?
Updated, as these were now released in 4.11.0, not 5.0.0
FYI, seems you're missing the 4.11.0 tag in the repo.
Ah yes good point. With regards to the tag, `v4.11.0` was released: https://github.com/mockito/mockito/releases/tag/v4.11.0
Yeah this is all fine. I mostly wanted to know why we were changing the test here, which all makes sense.

Patch that resolved the issue:
diff --git a/src/main/java/org/mockito/ArgumentMatcher.java b/src/main/java/org/mockito/ArgumentMatcher.java
index ad52e1ecae..5d68132d82 100644
--- a/src/main/java/org/mockito/ArgumentMatcher.java
+++ b/src/main/java/org/mockito/ArgumentMatcher.java
@@ -161,7 +161,7 @@ public interface ArgumentMatcher<T> {
      * <p>Only matcher implementations that can conceptually match a raw vararg parameter should override this method.
      *
      * @return the type this matcher handles. The default value of {@link Void} means the type is not known.
-     * @since 5.0.0
+     * @since 4.11.0
      */
     default Class<?> type() {
         return Void.class;
diff --git a/src/main/java/org/mockito/ArgumentMatchers.java b/src/main/java/org/mockito/ArgumentMatchers.java
index 28986e1648..1d3f11136f 100644
--- a/src/main/java/org/mockito/ArgumentMatchers.java
+++ b/src/main/java/org/mockito/ArgumentMatchers.java
@@ -174,7 +174,7 @@ public static <T> T any() {
      * @see #isNull()
      */
     public static <T> T any(Class<T> type) {
-        reportMatcher(new InstanceOf.VarArgAware(type, "<any " + type.getCanonicalName() + ">"));
+        reportMatcher(new InstanceOf(type, "<any " + type.getCanonicalName() + ">"));
         return defaultValue(type);
     }
 
@@ -709,7 +709,7 @@ public static <T> T isNull() {
      * @param type the type of the argument being matched.
      * @return <code>null</code>.
      * @see #isNotNull(Class)
-     * @since 5.0.0
+     * @since 4.11.0
      */
     public static <T> T isNull(Class<T> type) {
         reportMatcher(new Null<>(type));
@@ -747,7 +747,7 @@ public static <T> T notNull() {
      *
      * @param type the type of the argument being matched.
      * @return <code>null</code>.
-     * @since 5.0.0
+     * @since 4.11.0
      */
     public static <T> T notNull(Class<T> type) {
         reportMatcher(new NotNull<>(type));
@@ -786,7 +786,7 @@ public static <T> T isNotNull() {
      * @param type the type of the argument being matched.
      * @return <code>null</code>.
      * @see #isNull()
-     * @since 5.0.0
+     * @since 4.11.0
      */
     public static <T> T isNotNull(Class<T> type) {
         return notNull(type);
diff --git a/src/main/java/org/mockito/hamcrest/MockitoHamcrest.java b/src/main/java/org/mockito/hamcrest/MockitoHamcrest.java
index b8ebf8f97d..3624ba20c4 100644
--- a/src/main/java/org/mockito/hamcrest/MockitoHamcrest.java
+++ b/src/main/java/org/mockito/hamcrest/MockitoHamcrest.java
@@ -42,6 +42,24 @@
  * Due to how java works we don't really have a clean way of detecting this scenario and protecting the user from this problem.
  * Hopefully, the javadoc describes the problem and solution well.
  * If you have an idea how to fix the problem, let us know via the mailing list or the issue tracker.
+ * <p/>
+ * By default, a matcher passed to a varargs parameter will match against the first element in the varargs array.
+ * To match against the raw varargs array pass the type of the varargs parameter to {@link MockitoHamcrest#argThat(Matcher, Class)}
+ * <p/>
+ * For example, to match any number of {@code String} values:
+ * <pre>
+ *     import static org.hamcrest.CoreMatchers.isA;
+ *     import static org.mockito.hamcrest.MockitoHamcrest.argThat;
+ *
+ *     // Given:
+ *     void varargMethod(String... args);
+ *
+ *     //stubbing
+ *     when(mock.varargMethod(argThat(isA(String[].class), String[].class));
+ *
+ *     //verification
+ *     verify(mock).giveMe(argThat(isA(String[].class), String[].class));
+ * </pre>
  *
  * @since 2.1.0
  */
@@ -62,6 +80,26 @@ public static <T> T argThat(Matcher<T> matcher) {
         return (T) defaultValue(genericTypeOfMatcher(matcher.getClass()));
     }
 
+    /**
+     * Allows matching arguments with hamcrest matchers.
+     * <p/>
+     * This variant can be used to pass an explicit {@code type},
+     * which can be useful to provide a matcher that matches against all
+     * elements in a varargs parameter.
+     * <p/>
+     * See examples in javadoc for {@link MockitoHamcrest} class
+     *
+     * @param matcher decides whether argument matches
+     * @param type the type the matcher matches.
+     * @return <code>null</code> or default value for primitive (0, false, etc.)
+     * @since 5.0.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T argThat(Matcher<T> matcher, Class<T> type) {
+        reportMatcher(matcher, type);
+        return (T) defaultValue(genericTypeOfMatcher(matcher.getClass()));
+    }
+
     /**
      * Enables integrating hamcrest matchers that match primitive <code>char</code> arguments.
      * Note that {@link #argThat} will not work with primitive <code>char</code> matchers due to <code>NullPointerException</code> auto-unboxing caveat.
@@ -175,9 +213,15 @@ public static double doubleThat(Matcher<Double> matcher) {
     }
 
     private static <T> void reportMatcher(Matcher<T> matcher) {
-        mockingProgress()
-                .getArgumentMatcherStorage()
-                .reportMatcher(new HamcrestArgumentMatcher<T>(matcher));
+        reportMatcher(new HamcrestArgumentMatcher<T>(matcher));
+    }
+
+    private static <T> void reportMatcher(Matcher<T> matcher, Class<T> type) {
+        reportMatcher(new HamcrestArgumentMatcher<T>(matcher, type));
+    }
+
+    private static <T> void reportMatcher(final HamcrestArgumentMatcher<T> matcher) {
+        mockingProgress().getArgumentMatcherStorage().reportMatcher(matcher);
     }
 
     private MockitoHamcrest() {}
diff --git a/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java b/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
index db526546eb..f9ef55d528 100644
--- a/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
+++ b/src/main/java/org/mockito/internal/hamcrest/HamcrestArgumentMatcher.java
@@ -7,14 +7,25 @@
 import org.hamcrest.Matcher;
 import org.hamcrest.StringDescription;
 import org.mockito.ArgumentMatcher;
-import org.mockito.internal.matchers.VarargMatcher;
+
+import static java.util.Objects.requireNonNull;
 
 public class HamcrestArgumentMatcher<T> implements ArgumentMatcher<T> {
 
-    private final Matcher matcher;
+    private final Matcher<T> matcher;
+    private final Class<?> type;
 
     public HamcrestArgumentMatcher(Matcher<T> matcher) {
-        this.matcher = matcher;
+        this(Void.class, matcher);
+    }
+
+    public HamcrestArgumentMatcher(Matcher<T> matcher, Class<T> type) {
+        this(type, matcher);
+    }
+
+    private HamcrestArgumentMatcher(Class<?> type, Matcher<T> matcher) {
+        this.type = requireNonNull(type, "type");
+        this.matcher = requireNonNull(matcher, "matcher");
     }
 
     @Override
@@ -22,14 +33,14 @@ public boolean matches(Object argument) {
         return this.matcher.matches(argument);
     }
 
-    @SuppressWarnings("deprecation")
-    public boolean isVarargMatcher() {
-        return matcher instanceof VarargMatcher;
-    }
-
     @Override
     public String toString() {
         // TODO SF add unit tests and integ test coverage for toString()
         return StringDescription.toString(matcher);
     }
+
+    @Override
+    public Class<?> type() {
+        return type;
+    }
 }
diff --git a/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java b/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
index f3c0111c64..8b50da635d 100644
--- a/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
+++ b/src/main/java/org/mockito/internal/invocation/MatcherApplicationStrategy.java
@@ -4,13 +4,10 @@
  */
 package org.mockito.internal.invocation;
 
-import java.util.ArrayList;
 import java.util.List;
 
 import org.mockito.ArgumentMatcher;
-import org.mockito.internal.hamcrest.HamcrestArgumentMatcher;
 import org.mockito.internal.matchers.CapturingMatcher;
-import org.mockito.internal.matchers.VarargMatcher;
 import org.mockito.invocation.Invocation;
 
 public class MatcherApplicationStrategy {
@@ -63,7 +60,7 @@ public boolean forEachMatcherAndArgument(ArgumentMatcherAction action) {
                         && invocation.getRawArguments().length == matchers.size();
 
         if (maybeVararg) {
-            final Class<?> matcherType = lastMatcher().type();
+            final Class<?> matcherType = lastMatcherType();
             final Class<?> paramType = lastParameterType();
             if (paramType.isAssignableFrom(matcherType)) {
                 return argsMatch(invocation.getRawArguments(), matchers, action);
@@ -74,12 +71,6 @@ public boolean forEachMatcherAndArgument(ArgumentMatcherAction action) {
             return argsMatch(invocation.getArguments(), matchers, action);
         }
 
-        if (maybeVararg && isLastMatcherVarargMatcher()) {
-            int times = varargLength();
-            final List<? extends ArgumentMatcher<?>> matchers = appendLastMatcherNTimes(times);
-            return argsMatch(invocation.getArguments(), matchers, action);
-        }
-
         return false;
     }
 
@@ -98,33 +89,8 @@ private boolean argsMatch(
         return true;
     }
 
-    private boolean isLastMatcherVarargMatcher() {
-        ArgumentMatcher<?> argumentMatcher = lastMatcher();
-        if (argumentMatcher instanceof HamcrestArgumentMatcher<?>) {
-            return ((HamcrestArgumentMatcher<?>) argumentMatcher).isVarargMatcher();
-        }
-        return argumentMatcher instanceof VarargMatcher;
-    }
-
-    private List<? extends ArgumentMatcher<?>> appendLastMatcherNTimes(
-            int timesToAppendLastMatcher) {
-        ArgumentMatcher<?> lastMatcher = lastMatcher();
-
-        List<ArgumentMatcher<?>> expandedMatchers = new ArrayList<ArgumentMatcher<?>>(matchers);
-        for (int i = 0; i < timesToAppendLastMatcher; i++) {
-            expandedMatchers.add(lastMatcher);
-        }
-        return expandedMatchers;
-    }
-
-    private int varargLength() {
-        int rawArgumentCount = invocation.getRawArguments().length;
-        int expandedArgumentCount = invocation.getArguments().length;
-        return expandedArgumentCount - rawArgumentCount;
-    }
-
-    private ArgumentMatcher<?> lastMatcher() {
-        return matchers.get(matchers.size() - 1);
+    private Class<?> lastMatcherType() {
+        return matchers.get(matchers.size() - 1).type();
     }
 
     private Class<?> lastParameterType() {
diff --git a/src/main/java/org/mockito/internal/matchers/Any.java b/src/main/java/org/mockito/internal/matchers/Any.java
index 1a71a7e2bc..2074f81abc 100644
--- a/src/main/java/org/mockito/internal/matchers/Any.java
+++ b/src/main/java/org/mockito/internal/matchers/Any.java
@@ -8,7 +8,7 @@
 
 import org.mockito.ArgumentMatcher;
 
-public class Any implements ArgumentMatcher<Object>, VarargMatcher, Serializable {
+public class Any implements ArgumentMatcher<Object>, Serializable {
 
     public static final Any ANY = new Any();
 
diff --git a/src/main/java/org/mockito/internal/matchers/CapturingMatcher.java b/src/main/java/org/mockito/internal/matchers/CapturingMatcher.java
index 2be6d9f566..7ce9133651 100644
--- a/src/main/java/org/mockito/internal/matchers/CapturingMatcher.java
+++ b/src/main/java/org/mockito/internal/matchers/CapturingMatcher.java
@@ -17,8 +17,7 @@
 import org.mockito.ArgumentMatcher;
 import org.mockito.internal.util.Primitives;
 
-public class CapturingMatcher<T>
-        implements ArgumentMatcher<T>, CapturesArguments, VarargMatcher, Serializable {
+public class CapturingMatcher<T> implements ArgumentMatcher<T>, CapturesArguments, Serializable {
 
     private final Class<? extends T> clazz;
     private final List<T> arguments = new ArrayList<>();
diff --git a/src/main/java/org/mockito/internal/matchers/InstanceOf.java b/src/main/java/org/mockito/internal/matchers/InstanceOf.java
index 9ea762bb96..a53b1bda0f 100644
--- a/src/main/java/org/mockito/internal/matchers/InstanceOf.java
+++ b/src/main/java/org/mockito/internal/matchers/InstanceOf.java
@@ -39,20 +39,4 @@ public Class<?> type() {
     public String toString() {
         return description;
     }
-
-    public static class VarArgAware extends InstanceOf implements VarargMatcher {
-
-        public VarArgAware(Class<?> clazz) {
-            super(clazz);
-        }
-
-        public VarArgAware(Class<?> clazz, String describedAs) {
-            super(clazz, describedAs);
-        }
-
-        @Override
-        public Class<?> type() {
-            return clazz;
-        }
-    }
 }
diff --git a/src/main/java/org/mockito/internal/matchers/VarargMatcher.java b/src/main/java/org/mockito/internal/matchers/VarargMatcher.java
deleted file mode 100644
index 2dfd9b7549..0000000000
--- a/src/main/java/org/mockito/internal/matchers/VarargMatcher.java
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (c) 2007 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockito.internal.matchers;
-
-import java.io.Serializable;
-
-/**
- * Internal interface that informs Mockito that the matcher is intended to capture varargs.
- * This information is needed when mockito collects the arguments.
- *
- * @deprecated use of this interface is deprecated as the behaviour it promotes has limitations.
- * It is not recommended for new implementations to implement this method.
- *
- * <p>Instead, matchers should implement the {@link org.mockito.ArgumentMatcher#type()} method.
- * If this method returns the same raw type as a vararg parameter, then Mockito will treat the
- * matcher as matching the entire vararg array parameter, otherwise it will be treated as matching a single element.
- * For an example, see {@link org.mockito.ArgumentMatchers#isNull(Class)}.
- */
-@Deprecated
-public interface VarargMatcher extends Serializable {}


Test patch:
diff --git a/src/test/java/org/mockito/internal/invocation/InvocationMatcherTest.java b/src/test/java/org/mockito/internal/invocation/InvocationMatcherTest.java
index ab53be545f..a217d4d8d3 100644
--- a/src/test/java/org/mockito/internal/invocation/InvocationMatcherTest.java
+++ b/src/test/java/org/mockito/internal/invocation/InvocationMatcherTest.java
@@ -149,11 +149,11 @@ public void should_capture_arguments_from_invocation() throws Exception {
     }
 
     @Test
-    public void should_match_varargs_using_any_varargs() throws Exception {
+    public void should_match_varargs_using_any_varargs() {
         // given
         mock.varargs("1", "2");
         Invocation invocation = getLastInvocation();
-        InvocationMatcher invocationMatcher = new InvocationMatcher(invocation, (List) asList(ANY));
+        InvocationMatcher invocationMatcher = new InvocationMatcher(invocation, asList(ANY, ANY));
 
         // when
         boolean match = invocationMatcher.matches(invocation);
@@ -163,11 +163,11 @@ public void should_match_varargs_using_any_varargs() throws Exception {
     }
 
     @Test
-    public void should_capture_varargs_as_vararg() throws Exception {
+    public void should_capture_varargs_as_vararg() {
         // given
         mock.mixedVarargs(1, "a", "b");
         Invocation invocation = getLastInvocation();
-        CapturingMatcher m = new CapturingMatcher(List.class);
+        CapturingMatcher<String[]> m = new CapturingMatcher(String[].class);
         InvocationMatcher invocationMatcher =
                 new InvocationMatcher(invocation, Arrays.<ArgumentMatcher>asList(new Equals(1), m));
 
@@ -175,11 +175,11 @@ public void should_capture_varargs_as_vararg() throws Exception {
         invocationMatcher.captureArgumentsFrom(invocation);
 
         // then
-        Assertions.assertThat(m.getAllValues()).containsExactly("a", "b");
+        Assertions.assertThat(m.getAllValues()).containsExactly(new String[] {"a", "b"});
     }
 
     @Test // like using several time the captor in the vararg
-    public void should_capture_arguments_when_args_count_does_NOT_match() throws Exception {
+    public void should_capture_arguments_when_args_count_does_NOT_match() {
         // given
         mock.varargs();
         Invocation invocation = getLastInvocation();
diff --git a/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java b/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java
index ddd4333905..21c94b1525 100644
--- a/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java
+++ b/src/test/java/org/mockito/internal/invocation/MatcherApplicationStrategyTest.java
@@ -9,7 +9,6 @@
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.internal.invocation.MatcherApplicationStrategy.getMatcherApplicationStrategyFor;
 import static org.mockito.internal.matchers.Any.ANY;
 
@@ -26,7 +25,6 @@
 import org.mockito.internal.matchers.Any;
 import org.mockito.internal.matchers.Equals;
 import org.mockito.internal.matchers.InstanceOf;
-import org.mockito.internal.matchers.VarargMatcher;
 import org.mockito.invocation.Invocation;
 import org.mockitousage.IMethods;
 import org.mockitoutil.TestBase;
@@ -124,7 +122,7 @@ public void shouldKnowWhenVarargsMatch() {
     public void shouldAllowAnyMatchEntireVararg() {
         // given
         invocation = varargs("1", "2");
-        matchers = asList(ANY);
+        matchers = asList(ANY, ANY);
 
         // when
         boolean match =
@@ -151,10 +149,10 @@ public void shouldNotAllowAnyWithMixedVarargs() {
     }
 
     @Test
-    public void shouldAllowanyWithMixedVarargs() {
+    public void shouldAllowAnyWithMixedVarargs() {
         // given
         invocation = mixedVarargs(1, "1", "2");
-        matchers = asList(new Equals(1), ANY);
+        matchers = asList(new Equals(1), ANY, ANY);
 
         // when
         boolean match =
@@ -186,7 +184,7 @@ public void shouldAnyDealWithDifferentSizeOfArgs() {
     public void shouldMatchAnyEvenIfOneOfTheArgsIsNull() {
         // given
         invocation = mixedVarargs(null, null, "2");
-        matchers = asList(new Equals(null), ANY);
+        matchers = asList(new Equals(null), ANY, ANY);
 
         // when
         getMatcherApplicationStrategyFor(invocation, matchers)
@@ -200,7 +198,7 @@ public void shouldMatchAnyEvenIfOneOfTheArgsIsNull() {
     public void shouldMatchAnyEvenIfMatcherIsDecorated() {
         // given
         invocation = varargs("1", "2");
-        matchers = asList(ANY);
+        matchers = asList(ANY, ANY);
 
         // when
         getMatcherApplicationStrategyFor(invocation, matchers)
@@ -216,7 +214,7 @@ public void shouldMatchAnyEvenIfMatcherIsWrappedInHamcrestMatcher() {
         invocation = varargs("1", "2");
         HamcrestArgumentMatcher<Integer> argumentMatcher =
                 new HamcrestArgumentMatcher<>(new IntMatcher());
-        matchers = asList(argumentMatcher);
+        matchers = asList(argumentMatcher, argumentMatcher);
 
         // when
         getMatcherApplicationStrategyFor(invocation, matchers)
@@ -230,7 +228,7 @@ public void shouldMatchAnyEvenIfMatcherIsWrappedInHamcrestMatcher() {
     public void shouldMatchAnyThatMatchesRawVarArgType() {
         // given
         invocation = varargs("1", "2");
-        InstanceOf.VarArgAware any = new InstanceOf.VarArgAware(String[].class, "<any String[]>");
+        InstanceOf any = new InstanceOf(String[].class, "<any String[]>");
         matchers = asList(any);
 
         // when
@@ -241,7 +239,15 @@ public void shouldMatchAnyThatMatchesRawVarArgType() {
         recordAction.assertContainsExactly(any);
     }
 
-    private static class IntMatcher extends BaseMatcher<Integer> implements VarargMatcher {
+    private static class IntMatcher extends BaseMatcher<Integer> {
+        public boolean matches(Object o) {
+            return true;
+        }
+
+        public void describeTo(Description description) {}
+    }
+
+    private static class IntArrayMatcher extends BaseMatcher<Integer[]> {
         public boolean matches(Object o) {
             return true;
         }
diff --git a/src/test/java/org/mockito/internal/matchers/InstanceOfTest.java b/src/test/java/org/mockito/internal/matchers/InstanceOfTest.java
index 8addef8ca0..7740d0b77d 100644
--- a/src/test/java/org/mockito/internal/matchers/InstanceOfTest.java
+++ b/src/test/java/org/mockito/internal/matchers/InstanceOfTest.java
@@ -59,9 +59,8 @@ public void should_check_for_primitive_wrapper_types() {
 
     @Test
     public void can_be_vararg_aware() {
-        assertThat(new InstanceOf.VarArgAware(Number[].class)).isInstanceOf(VarargMatcher.class);
-        assertThat(new InstanceOf.VarArgAware(Number[].class).matches(new Integer[0])).isTrue();
-        assertThat(new InstanceOf.VarArgAware(Number[].class).matches(new Number[0])).isTrue();
-        assertThat(new InstanceOf.VarArgAware(Number[].class).matches(new Object[0])).isFalse();
+        assertThat(new InstanceOf(Number[].class).matches(new Integer[0])).isTrue();
+        assertThat(new InstanceOf(Number[].class).matches(new Number[0])).isTrue();
+        assertThat(new InstanceOf(Number[].class).matches(new Object[0])).isFalse();
     }
 }
diff --git a/src/test/java/org/mockito/internal/util/reflection/ParameterizedConstructorInstantiatorTest.java b/src/test/java/org/mockito/internal/util/reflection/ParameterizedConstructorInstantiatorTest.java
index 9e63e8df69..45ff5ea86f 100644
--- a/src/test/java/org/mockito/internal/util/reflection/ParameterizedConstructorInstantiatorTest.java
+++ b/src/test/java/org/mockito/internal/util/reflection/ParameterizedConstructorInstantiatorTest.java
@@ -73,7 +73,7 @@ public void should_be_created_with_an_argument_resolver() throws Exception {
     public void should_instantiate_type_if_resolver_provide_matching_types() throws Exception {
         Observer observer = mock(Observer.class);
         Map map = mock(Map.class);
-        given(resolver.resolveTypeInstances(ArgumentMatchers.<Class<?>[]>any()))
+        given(resolver.resolveTypeInstances(ArgumentMatchers.any(Class[].class)))
                 .willReturn(new Object[] {observer, map});
 
         new ParameterizedConstructorInstantiator(this, field("withMultipleConstructor"), resolver)
@@ -120,7 +120,7 @@ this, field("withThrowingConstructor"), resolver)
     @Test
     public void should_instantiate_type_with_vararg_constructor() throws Exception {
         Observer[] vararg = new Observer[] {};
-        given(resolver.resolveTypeInstances(ArgumentMatchers.<Class<?>[]>any()))
+        given(resolver.resolveTypeInstances(ArgumentMatchers.any(Class[].class)))
                 .willReturn(new Object[] {"", vararg});
 
         new ParameterizedConstructorInstantiator(this, field("withVarargConstructor"), resolver)
diff --git a/src/test/java/org/mockitousage/basicapi/UsingVarargsTest.java b/src/test/java/org/mockitousage/basicapi/UsingVarargsTest.java
index 551c63790a..8d69a2a52f 100644
--- a/src/test/java/org/mockitousage/basicapi/UsingVarargsTest.java
+++ b/src/test/java/org/mockitousage/basicapi/UsingVarargsTest.java
@@ -173,9 +173,9 @@ public void shouldStubCorrectlyWhenDoubleStringAndMixedVarargsUsed() {
 
     @Test
     // See bug #157
-    public void shouldMatchEasilyEmptyVararg() throws Exception {
+    public void shouldMatchEasilyEmptyVararg() {
         // when
-        when(mock.foo(any())).thenReturn(-1);
+        when(mock.foo(any(Object[].class))).thenReturn(-1);
 
         // then
         assertEquals(-1, mock.foo());
diff --git a/src/test/java/org/mockitousage/bugs/varargs/VarargsAndAnyPicksUpExtraInvocationsTest.java b/src/test/java/org/mockitousage/bugs/varargs/VarargsAndAnyPicksUpExtraInvocationsTest.java
index f6f4417c4a..c08bdf0643 100644
--- a/src/test/java/org/mockitousage/bugs/varargs/VarargsAndAnyPicksUpExtraInvocationsTest.java
+++ b/src/test/java/org/mockitousage/bugs/varargs/VarargsAndAnyPicksUpExtraInvocationsTest.java
@@ -26,7 +26,7 @@ public void shouldVerifyCorrectlyWithAny() {
         table.newRow("abc", "def");
 
         // then
-        verify(table, times(2)).newRow(anyString(), (String[]) any());
+        verify(table, times(2)).newRow(anyString(), any(String[].class));
     }
 
     @Test
@@ -36,7 +36,7 @@ public void shouldVerifyCorrectlyNumberOfInvocationsUsingAnyAndEqualArgument() {
         table.newRow("x", "def");
 
         // then
-        verify(table, times(2)).newRow(eq("x"), (String[]) any());
+        verify(table, times(2)).newRow(eq("x"), any(String[].class));
     }
 
     @Test
diff --git a/src/test/java/org/mockitousage/bugs/varargs/VarargsNotPlayingWithAnyTest.java b/src/test/java/org/mockitousage/bugs/varargs/VarargsNotPlayingWithAnyTest.java
deleted file mode 100644
index 6e11a6a7fd..0000000000
--- a/src/test/java/org/mockitousage/bugs/varargs/VarargsNotPlayingWithAnyTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2007 Mockito contributors
- * This program is made available under the terms of the MIT License.
- */
-package org.mockitousage.bugs.varargs;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyString;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockitoutil.TestBase;
-
-// see issue 62
-public class VarargsNotPlayingWithAnyTest extends TestBase {
-
-    interface VarargMethod {
-        Object run(String... args);
-    }
-
-    @Mock VarargMethod mock;
-
-    @Test
-    public void shouldMatchAny() {
-        mock.run("a", "b");
-
-        verify(mock).run(anyString(), anyString());
-        verify(mock).run((String) any(), (String) any());
-
-        verify(mock).run((String[]) any());
-
-        verify(mock, never()).run();
-        verify(mock, never()).run(anyString(), eq("f"));
-    }
-
-    @Test
-    public void shouldAllowUsinganyForVarArgs() {
-        mock.run("a", "b");
-        verify(mock).run((String[]) any());
-    }
-
-    @Test
-    public void shouldStubUsingAny() {
-        when(mock.run((String[]) any())).thenReturn("foo");
-
-        assertEquals("foo", mock.run("a", "b"));
-    }
-}
diff --git a/src/test/java/org/mockitousage/matchers/CapturingArgumentsTest.java b/src/test/java/org/mockitousage/matchers/CapturingArgumentsTest.java
index 34b8684883..e0146de780 100644
--- a/src/test/java/org/mockitousage/matchers/CapturingArgumentsTest.java
+++ b/src/test/java/org/mockitousage/matchers/CapturingArgumentsTest.java
@@ -4,6 +4,7 @@
  */
 package org.mockitousage.matchers;
 
+import static java.util.Arrays.asList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.*;
@@ -13,7 +14,6 @@
 import java.util.List;
 import java.util.Set;
 
-import org.assertj.core.api.Assertions;
 import org.junit.Test;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
@@ -24,7 +24,7 @@
 
 public class CapturingArgumentsTest extends TestBase {
 
-    class Person {
+    private static class Person {
 
         private final Integer age;
 
@@ -37,9 +37,9 @@ public int getAge() {
         }
     }
 
-    class BulkEmailService {
+    private static class BulkEmailService {
 
-        private EmailService service;
+        private final EmailService service;
 
         public BulkEmailService(EmailService service) {
             this.service = service;
@@ -62,7 +62,6 @@ interface EmailService {
     private final IMethods mock = mock(IMethods.class);
     @Captor private ArgumentCaptor<List<?>> listCaptor;
 
-    @SuppressWarnings("deprecation")
     @Test
     public void should_allow_assertions_on_captured_argument() {
         // given
@@ -171,7 +170,7 @@ public void should_capture_when_stubbing_only_when_entire_invocation_matches() {
         mock.simpleMethod("bar", 2);
 
         // then
-        Assertions.assertThat(argument.getAllValues()).containsOnly("bar");
+        assertThat(argument.getAllValues()).containsOnly("bar");
     }
 
     @Test
@@ -243,12 +242,41 @@ public void should_capture_byte_vararg_by_creating_captor_with_primitive() {
         ArgumentCaptor<Byte> argumentCaptor = ArgumentCaptor.forClass(byte.class);
 
         // when
-        mock.varargsbyte((byte) 1, (byte) 2);
+        mock.varargsbyte((byte) 1);
 
         // then
         verify(mock).varargsbyte(argumentCaptor.capture());
+        assertEquals((byte) 1, (byte) argumentCaptor.getValue());
+        assertThat(argumentCaptor.getAllValues()).containsExactly((byte) 1);
+    }
+
+    @Test
+    public void should_capture_byte_vararg_by_creating_captor_with_primitive_2_args() {
+        // given
+        ArgumentCaptor<Byte> argumentCaptor = ArgumentCaptor.forClass(byte.class);
+
+        // when
+        mock.varargsbyte((byte) 1, (byte) 2);
+
+        // then
+        verify(mock).varargsbyte(argumentCaptor.capture(), argumentCaptor.capture());
         assertEquals((byte) 2, (byte) argumentCaptor.getValue());
-        Assertions.assertThat(argumentCaptor.getAllValues()).containsExactly((byte) 1, (byte) 2);
+        assertThat(argumentCaptor.getAllValues()).containsExactly((byte) 1, (byte) 2);
+    }
+
+    @Test
+    public void should_capture_byte_vararg_by_creating_captor_with_primitive_array() {
+        // given
+        ArgumentCaptor<byte[]> argumentCaptor = ArgumentCaptor.forClass(byte[].class);
+
+        // when
+        mock.varargsbyte();
+        mock.varargsbyte((byte) 1, (byte) 2);
+
+        // then
+        verify(mock, times(2)).varargsbyte(argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).containsExactly(new byte[] {1, 2});
+        assertThat(argumentCaptor.getAllValues()).containsExactly(new byte[] {}, new byte[] {1, 2});
     }
 
     @Test
@@ -257,41 +285,163 @@ public void should_capture_byte_vararg_by_creating_captor_with_primitive_wrapper
         ArgumentCaptor<Byte> argumentCaptor = ArgumentCaptor.forClass(Byte.class);
 
         // when
-        mock.varargsbyte((byte) 1, (byte) 2);
+        mock.varargsbyte((byte) 1);
 
         // then
         verify(mock).varargsbyte(argumentCaptor.capture());
-        assertEquals((byte) 2, (byte) argumentCaptor.getValue());
-        Assertions.assertThat(argumentCaptor.getAllValues()).containsExactly((byte) 1, (byte) 2);
+        assertEquals((byte) 1, (byte) argumentCaptor.getValue());
+        assertThat(argumentCaptor.getAllValues()).containsExactly((byte) 1);
     }
 
     @Test
-    public void should_capture_vararg() {
+    public void should_not_capture_empty_vararg_with_single_captor() {
         // given
         ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
 
         // when
-        mock.mixedVarargs(42, "a", "b", "c");
+        mock.mixedVarargs(42);
+
+        // then
+        verify(mock, never()).mixedVarargs(any(), argumentCaptor.capture());
+    }
+
+    @Test
+    public void should_capture_single_vararg_with_single_captor() {
+        // given
+        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
+
+        // when
+        mock.mixedVarargs(42, "a");
 
         // then
         verify(mock).mixedVarargs(any(), argumentCaptor.capture());
-        Assertions.assertThat(argumentCaptor.getAllValues()).containsExactly("a", "b", "c");
+        assertThat(argumentCaptor.getValue()).isEqualTo("a");
+    }
+
+    @Test
+    public void should_not_capture_multiple_vararg_with_single_captor() {
+        // given
+        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
+
+        // when
+        mock.mixedVarargs(42, "a", "b");
+
+        // then
+        verify(mock, never()).mixedVarargs(any(), argumentCaptor.capture());
     }
 
     @Test
-    public void should_capture_all_vararg() {
+    public void should_capture_multiple_vararg_with_multiple_captor() {
         // given
         ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
 
+        // when
+        mock.mixedVarargs(42, "a", "b");
+
+        // then
+        verify(mock).mixedVarargs(any(), argumentCaptor.capture(), argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).isEqualTo("b");
+        assertThat(argumentCaptor.getAllValues()).isEqualTo(asList("a", "b"));
+    }
+
+    @Test
+    public void should_not_capture_multiple_vararg_some_null_with_single_captor() {
+        // given
+        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
+
+        // when
+        mock.mixedVarargs(42, "a", null);
+
+        // then
+        verify(mock, never()).mixedVarargs(any(), argumentCaptor.capture());
+    }
+
+    @Test
+    public void should_capture_empty_vararg_with_array_captor() {
+        // given
+        ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+
+        // when
+        mock.mixedVarargs(42);
+
+        // then
+        verify(mock).mixedVarargs(any(), argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).isEqualTo(new String[] {});
+        assertThat(argumentCaptor.getAllValues()).containsExactly(new String[] {});
+    }
+
+    @Test
+    public void should_capture_single_vararg_with_array_captor() {
+        // given
+        ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+
+        // when
+        mock.mixedVarargs(42, "a");
+
+        // then
+        verify(mock).mixedVarargs(any(), argumentCaptor.capture());
+        assertThat(argumentCaptor.getValue()).isEqualTo(new String[] {"a"});
+        assertThat(argumentCaptor.getAllValues()).containsExactly(new String[] {"a"});
+    }
+
+    @Test
+    public void should_capture_multiple_vararg_with_array_captor() {
+        // given
+        ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+
         // when
         mock.mixedVarargs(42, "a", "b", "c");
-        mock.mixedVarargs(42, "again ?!");
+
+        // then
+        verify(mock).mixedVarargs(any(), argumentCaptor.capture());
+        assertThat(argumentCaptor.getAllValues()).containsExactly(new String[] {"a", "b", "c"});
+    }
+
+    @Test
+    public void should_capture_multiple_vararg_some_null_with_array_captor() {
+        // given
+        ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+
+        // when
+        mock.mixedVarargs(42, "a", null, "c");
+
+        // then
+        verify(mock).mixedVarargs(any(), argumentCaptor.capture());
+        assertThat(argumentCaptor.getAllValues()).containsExactly(new String[] {"a", null, "c"});
+    }
+
+    @Test
+    public void should_capture_multiple_invocations_with_captor() {
+        // given
+        ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
+
+        // when
+        mock.mixedVarargs(42, "a", "b");
+        mock.mixedVarargs(42, "c", "d");
+
+        // then
+        verify(mock, times(2))
+                .mixedVarargs(any(), argumentCaptor.capture(), argumentCaptor.capture());
+
+        assertThat(argumentCaptor.getValue()).isEqualTo("d");
+        assertThat(argumentCaptor.getAllValues()).containsExactly("a", "b", "c", "d");
+    }
+
+    @Test
+    public void should_capture_multiple_invocations_with_array_captor() {
+        // given
+        ArgumentCaptor<String[]> argumentCaptor = ArgumentCaptor.forClass(String[].class);
+
+        // when
+        mock.mixedVarargs(42, "a", "b");
+        mock.mixedVarargs(42, "c", "d");
 
         // then
         verify(mock, times(2)).mixedVarargs(any(), argumentCaptor.capture());
 
-        Assertions.assertThat(argumentCaptor.getAllValues())
-                .containsExactly("a", "b", "c", "again ?!");
+        assertThat(argumentCaptor.getValue()).isEqualTo(new String[] {"c", "d"});
+        assertThat(argumentCaptor.getAllValues())
+                .containsExactly(new String[] {"a", "b"}, new String[] {"c", "d"});
     }
 
     @Test
@@ -304,7 +454,7 @@ public void should_capture_one_arg_even_when_using_vararg_captor_on_nonvararg_me
 
         // then
         verify(mock).simpleMethod(argumentCaptor.capture(), eq(2));
-        Assertions.assertThat(argumentCaptor.getAllValues()).containsExactly("a");
+        assertThat(argumentCaptor.getAllValues()).containsExactly("a");
     }
 
     @Test
@@ -323,7 +473,7 @@ public void captures_correctly_when_captor_used_multiple_times() {
                         argumentCaptor.capture(),
                         argumentCaptor.capture(),
                         argumentCaptor.capture());
-        Assertions.assertThat(argumentCaptor.getAllValues()).containsExactly("a", "b", "c");
+        assertThat(argumentCaptor.getAllValues()).containsExactly("a", "b", "c");
     }
 
     @Test
@@ -336,7 +486,7 @@ public void captures_correctly_when_captor_used_on_pure_vararg_method() {
 
         // then
         verify(mock).varargs(eq(42), argumentCaptor.capture());
-        Assertions.assertThat(argumentCaptor.getValue()).contains("capturedValue");
+        assertThat(argumentCaptor.getValue()).contains("capturedValue");
     }
 
     @SuppressWarnings("unchecked")
diff --git a/src/test/java/org/mockitousage/matchers/HamcrestMatchersTest.java b/src/test/java/org/mockitousage/matchers/HamcrestMatchersTest.java
index 3f16618c2f..261a3c3c96 100644
--- a/src/test/java/org/mockitousage/matchers/HamcrestMatchersTest.java
+++ b/src/test/java/org/mockitousage/matchers/HamcrestMatchersTest.java
@@ -6,7 +6,10 @@
 
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.isA;
 import static org.junit.Assert.*;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.hamcrest.MockitoHamcrest.*;
@@ -54,7 +57,44 @@ public void verifies_with_hamcrest_matcher() {
         }
     }
 
-    private class IntMatcher extends BaseMatcher<Integer> {
+    @Test
+    public void does_not_verify_vararg_with_no_items() {
+        mock.varargs();
+
+        verify(mock, never()).varargs(argThat(isA(String.class)));
+    }
+
+    @Test
+    public void verifies_vararg_with_single_item() {
+        mock.varargs("a");
+
+        verify(mock).varargs(argThat(isA(String.class)));
+    }
+
+    @Test
+    public void does_not_verify_vararg_with_multiple_items() {
+        mock.varargs("a", "b");
+
+        verify(mock, never()).varargs(argThat(isA(String.class)));
+    }
+
+    @Test
+    public void verify_vararg_with_multiple_item() {
+        mock.varargs("a", "b");
+
+        verify(mock).varargs(argThat(isA(String.class)), argThat(isA(String.class)));
+    }
+
+    @Test
+    public void verifies_vararg_with_any_num_items() {
+        mock.varargs();
+        mock.varargs("a");
+        mock.varargs("a", "b");
+
+        verify(mock, times(3)).varargs(argThat(isA(String[].class), String[].class));
+    }
+
+    private final class IntMatcher extends BaseMatcher<Integer> {
         public boolean matches(Object o) {
             return true;
         }
diff --git a/src/test/java/org/mockitousage/matchers/VarargsTest.java b/src/test/java/org/mockitousage/matchers/VarargsTest.java
index 0e5456fd2f..5daba370eb 100644
--- a/src/test/java/org/mockitousage/matchers/VarargsTest.java
+++ b/src/test/java/org/mockitousage/matchers/VarargsTest.java
@@ -40,6 +40,7 @@ public class VarargsTest {
 
     @Rule public MockitoRule mockitoRule = MockitoJUnit.rule();
     @Captor private ArgumentCaptor<String> captor;
+    @Captor private ArgumentCaptor<String[]> arrayCaptor;
     @Mock private IMethods mock;
 
     private static final Condition<Object> NULL =
@@ -82,18 +83,18 @@ public void shouldMatchVarArgs_oneNullArg_eqNull() {
 
     @Test
     public void shouldMatchVarArgs_oneNullArg_isNull() {
-        Object arg = null;
-        mock.varargs(arg);
+        mock.varargs((Object) null);
 
-        verify(mock).varargs(ArgumentMatchers.<Object[]>isNull());
+        verify(mock).varargs(ArgumentMatchers.<Object>isNull());
+        verify(mock, never()).varargs(isNull(Object[].class));
     }
 
     @Test
     public void shouldMatchVarArgs_nullArrayArg() {
-        Object[] argArray = null;
-        mock.varargs(argArray);
+        mock.varargs((Object[]) null);
 
-        verify(mock).varargs(ArgumentMatchers.<Object[]>isNull());
+        verify(mock).varargs(isNull(Object[].class));
+        verify(mock).varargs(ArgumentMatchers.<Object>isNull());
     }
 
     @Test
@@ -111,28 +112,28 @@ public void shouldnotMatchVarArgs_twoArgsOneMatcher() {
     public void shouldMatchVarArgs_emptyVarArgsOneAnyMatcher() {
         mock.varargs();
 
-        verify(mock).varargs((String[]) any()); // any() -> VarargMatcher
+        verify(mock).varargs(any(String[].class));
     }
 
     @Test
     public void shouldMatchVarArgs_oneArgsOneAnyMatcher() {
         mock.varargs(1);
 
-        verify(mock).varargs(ArgumentMatchers.<Object[]>any()); // any() -> VarargMatcher
+        verify(mock).varargs(any(Object[].class));
     }
 
     @Test
     public void shouldMatchVarArgs_twoArgsOneAnyMatcher() {
         mock.varargs(1, 2);
 
-        verify(mock).varargs(ArgumentMatchers.<Object[]>any()); // any() -> VarargMatcher
+        verify(mock).varargs(any(Object[].class));
     }
 
     @Test
     public void shouldMatchVarArgs_twoArgsTwoAnyMatcher() {
         mock.varargs(1, 2);
 
-        verify(mock).varargs(any(), ArgumentMatchers.<Object>any()); // any() -> VarargMatcher
+        verify(mock).varargs(any(), ArgumentMatchers.<Object>any());
     }
 
     @Test
@@ -141,7 +142,7 @@ public void shouldMatchVarArgs_twoArgsThreeAnyMatcher() {
 
         assertThatThrownBy(
                         () -> {
-                            verify(mock).varargs(any(), any(), any()); // any() -> VarargMatcher
+                            verify(mock).varargs(any(), any(), any());
                         })
                 .hasMessageContaining("Argument(s) are different");
     }
@@ -192,9 +193,9 @@ public void shouldMatchVarArgs_oneArgIsNotNull() {
     public void shouldCaptureVarArgs_noArgs() {
         mock.varargs();
 
-        verify(mock).varargs(captor.capture());
+        verify(mock).varargs(arrayCaptor.capture());
 
-        assertThatCaptor(captor).isEmpty();
+        assertThatCaptor(arrayCaptor).contains(new String[] {});
     }
 
     @Test
@@ -224,9 +225,9 @@ public void shouldCaptureVarArgs_nullArrayArg() {
     public void shouldCaptureVarArgs_twoArgsOneCapture() {
         mock.varargs("1", "2");
 
-        verify(mock).varargs(captor.capture());
+        verify(mock).varargs(arrayCaptor.capture());
 
-        assertThatCaptor(captor).contains("1", "2");
+        assertThatCaptor(arrayCaptor).contains(new String[] {"1", "2"});
     }
 
     @Test
@@ -238,15 +239,6 @@ public void shouldCaptureVarArgs_twoArgsTwoCaptures() {
         assertThatCaptor(captor).contains("1", "2");
     }
 
-    @Test
-    public void shouldCaptureVarArgs_oneNullArgument() {
-        mock.varargs("1", null);
-
-        verify(mock).varargs(captor.capture());
-
-        assertThatCaptor(captor).contains("1", (String) null);
-    }
-
     @Test
     public void shouldCaptureVarArgs_oneNullArgument2() {
         mock.varargs("1", null);
@@ -363,20 +355,6 @@ public void shouldMockVarargsInvocation_multiple_vararg_matcher() {
         assertThat(mock.methodWithVarargAndNonVarargVariants("a", "b", "c")).isNull();
     }
 
-    @Test
-    public void shouldMockVarargsInvocationUsingCasts() {
-        given(mock.methodWithVarargAndNonVarargVariants((String) any()))
-                .willReturn("single arg method");
-        given(mock.methodWithVarargAndNonVarargVariants((String[]) any()))
-                .willReturn("var arg method");
-
-        assertThat(mock.methodWithVarargAndNonVarargVariants("a")).isEqualTo("single arg method");
-        assertThat(mock.methodWithVarargAndNonVarargVariants()).isEqualTo("var arg method");
-        assertThat(mock.methodWithVarargAndNonVarargVariants(new String[] {"a"}))
-                .isEqualTo("var arg method");
-        assertThat(mock.methodWithVarargAndNonVarargVariants("a", "b")).isEqualTo("var arg method");
-    }
-
     @Test
     public void shouldMockVarargsInvocationForSuperType() {
         given(mock.varargsReturningString(any(Object[].class))).willReturn("a");
diff --git a/src/test/java/org/mockitousage/stubbing/StubbingWithAdditionalAnswersTest.java b/src/test/java/org/mockitousage/stubbing/StubbingWithAdditionalAnswersTest.java
index d037cfc0a0..2b96bdf0a9 100644
--- a/src/test/java/org/mockitousage/stubbing/StubbingWithAdditionalAnswersTest.java
+++ b/src/test/java/org/mockitousage/stubbing/StubbingWithAdditionalAnswersTest.java
@@ -56,7 +56,8 @@ public void can_return_arguments_of_invocation() throws Exception {
         given(iMethods.objectArgMethod(any())).will(returnsFirstArg());
         given(iMethods.threeArgumentMethod(eq(0), any(), anyString())).will(returnsSecondArg());
         given(iMethods.threeArgumentMethod(eq(1), any(), anyString())).will(returnsLastArg());
-        given(iMethods.mixedVarargsReturningString(eq(1), any())).will(returnsArgAt(2));
+        given(iMethods.mixedVarargsReturningString(eq(1), any(String[].class)))
+                .will(returnsArgAt(2));
 
         assertThat(iMethods.objectArgMethod("first")).isEqualTo("first");
         assertThat(iMethods.threeArgumentMethod(0, "second", "whatever")).isEqualTo("second");
@@ -66,8 +67,10 @@ public void can_return_arguments_of_invocation() throws Exception {
 
     @Test
     public void can_return_var_arguments_of_invocation() throws Exception {
-        given(iMethods.mixedVarargsReturningStringArray(eq(1), any())).will(returnsLastArg());
-        given(iMethods.mixedVarargsReturningObjectArray(eq(1), any())).will(returnsArgAt(1));
+        given(iMethods.mixedVarargsReturningStringArray(eq(1), any(String[].class)))
+                .will(returnsLastArg());
+        given(iMethods.mixedVarargsReturningObjectArray(eq(1), any(String[].class)))
+                .will(returnsArgAt(1));
 
         assertThat(iMethods.mixedVarargsReturningStringArray(1, "the", "var", "args"))
                 .containsExactlyInAnyOrder("the", "var", "args");
@@ -77,7 +80,8 @@ public void can_return_var_arguments_of_invocation() throws Exception {
 
     @Test
     public void returns_arg_at_throws_on_out_of_range_var_args() throws Exception {
-        given(iMethods.mixedVarargsReturningString(eq(1), any())).will(returnsArgAt(3));
+        given(iMethods.mixedVarargsReturningString(eq(1), any(String[].class)))
+                .will(returnsArgAt(3));
 
         assertThatThrownBy(() -> iMethods.mixedVarargsReturningString(1, "a", "b"))
                 .isInstanceOf(MockitoException.class)
@@ -111,7 +115,7 @@ public void can_return_after_delay() throws Exception {
 
     @Test
     public void can_return_expanded_arguments_of_invocation() throws Exception {
-        given(iMethods.varargsObject(eq(1), any())).will(returnsArgAt(3));
+        given(iMethods.varargsObject(eq(1), any(Object[].class))).will(returnsArgAt(3));
 
         assertThat(iMethods.varargsObject(1, "bob", "alexander", "alice", "carl"))
                 .isEqualTo("alice");
@@ -389,7 +393,7 @@ public void answer(
     @Test
     public void can_return_based_on_strongly_types_one_parameter_var_args_function()
             throws Exception {
-        given(iMethods.varargs(any()))
+        given(iMethods.varargs(any(String[].class)))
                 .will(
                         answer(
                                 new Answer1<Integer, String[]>() {
@@ -406,7 +410,7 @@ public void will_execute_a_void_based_on_strongly_typed_one_parameter_var_args_f
             throws Exception {
         final IMethods target = mock(IMethods.class);
 
-        given(iMethods.varargs(any()))
+        given(iMethods.varargs(any(String[].class)))
                 .will(
                         answerVoid(
                                 new VoidAnswer1<String[]>() {
@@ -425,7 +429,7 @@ public void answer(String[] s) {
     @Test
     public void can_return_based_on_strongly_typed_two_parameter_var_args_function()
             throws Exception {
-        given(iMethods.mixedVarargsReturningString(any(), any()))
+        given(iMethods.mixedVarargsReturningString(any(), any(String[].class)))
                 .will(
                         answer(
                                 new Answer2<String, Object, String[]>() {
@@ -442,7 +446,7 @@ public void will_execute_a_void_based_on_strongly_typed_two_parameter_var_args_f
             throws Exception {
         final IMethods target = mock(IMethods.class);
 
-        given(iMethods.mixedVarargsReturningString(any(), any()))
+        given(iMethods.mixedVarargsReturningString(any(), any(String[].class)))
                 .will(
                         answerVoid(
                                 new VoidAnswer2<Object, String[]>() {
@@ -463,7 +467,7 @@ public void can_return_based_on_strongly_typed_three_parameter_var_args_function
             throws Exception {
         final IMethods target = mock(IMethods.class);
 
-        given(iMethods.threeArgumentVarArgsMethod(anyInt(), any(), any()))
+        given(iMethods.threeArgumentVarArgsMethod(anyInt(), any(), any(String[].class)))
                 .will(
                         answer(
                                 new Answer3<String, Integer, String, String[]>() {
@@ -486,7 +490,7 @@ public void will_execute_a_void_based_on_strongly_typed_three_parameter_var_args
             throws Exception {
         final IMethods target = mock(IMethods.class);
 
-        given(iMethods.threeArgumentVarArgsMethod(anyInt(), any(), any()))
+        given(iMethods.threeArgumentVarArgsMethod(anyInt(), any(), any(String[].class)))
                 .will(
                         answerVoid(
                                 new VoidAnswer3<Integer, String, String[]>() {
@@ -506,7 +510,7 @@ public void answer(Integer i, String s1, String[] s2) {
     public void can_return_based_on_strongly_typed_four_parameter_var_args_function()
             throws Exception {
         final IMethods target = mock(IMethods.class);
-        given(iMethods.fourArgumentVarArgsMethod(anyInt(), any(), anyInt(), any()))
+        given(iMethods.fourArgumentVarArgsMethod(anyInt(), any(), anyInt(), any(String[].class)))
                 .will(
                         answer(
                                 new Answer4<String, Integer, String, Integer, String[]>() {
@@ -531,7 +535,7 @@ public void will_execute_a_void_based_on_strongly_typed_four_parameter_var_args_
             throws Exception {
         final IMethods target = mock(IMethods.class);
 
-        given(iMethods.fourArgumentVarArgsMethod(anyInt(), any(), anyInt(), any()))
+        given(iMethods.fourArgumentVarArgsMethod(anyInt(), any(), anyInt(), any(String[].class)))
                 .will(
                         answerVoid(
                                 new VoidAnswer4<Integer, String, Integer, String[]>() {
@@ -552,7 +556,9 @@ public void answer(
     public void can_return_based_on_strongly_typed_five_parameter_var_args_function()
             throws Exception {
         final IMethods target = mock(IMethods.class);
-        given(iMethods.fiveArgumentVarArgsMethod(anyInt(), any(), anyInt(), any(), any()))
+        given(
+                        iMethods.fiveArgumentVarArgsMethod(
+                                anyInt(), any(), anyInt(), any(), any(String[].class)))
                 .will(
                         answer(
                                 new Answer5<String, Integer, String, Integer, String, String[]>() {
@@ -580,7 +586,9 @@ public void will_execute_a_void_based_on_strongly_typed_five_parameter_var_args_
             throws Exception {
         final IMethods target = mock(IMethods.class);
 
-        given(iMethods.fiveArgumentVarArgsMethod(anyInt(), any(), anyInt(), any(), any()))
+        given(
+                        iMethods.fiveArgumentVarArgsMethod(
+                                anyInt(), any(), anyInt(), any(), any(String[].class)))
                 .will(
                         answerVoid(
                                 new VoidAnswer5<Integer, String, Integer, String, String[]>() {
@@ -605,7 +613,9 @@ public void answer(
     public void can_return_based_on_strongly_typed_six_parameter_var_args_function()
             throws Exception {
         final IMethods target = mock(IMethods.class);
-        given(iMethods.sixArgumentVarArgsMethod(anyInt(), any(), anyInt(), any(), any(), any()))
+        given(
+                        iMethods.sixArgumentVarArgsMethod(
+                                anyInt(), any(), anyInt(), any(), any(), any(String[].class)))
                 .will(
                         answer(
                                 new Answer6<
@@ -641,7 +651,9 @@ public String answer(
     public void will_execute_a_void_returning_strongly_typed_six_parameter_var_args_function()
             throws Exception {
         final IMethods target = mock(IMethods.class);
-        given(iMethods.sixArgumentVarArgsMethod(anyInt(), any(), anyInt(), any(), any(), any()))
+        given(
+                        iMethods.sixArgumentVarArgsMethod(
+                                anyInt(), any(), anyInt(), any(), any(), any(String[].class)))
                 .will(
                         answerVoid(
                                 new VoidAnswer6<
@@ -667,7 +679,7 @@ public void answer(
 
     @Test
     public void can_accept_array_supertype_for_strongly_typed_var_args_function() throws Exception {
-        given(iMethods.varargs(any()))
+        given(iMethods.varargs(any(String[].class)))
                 .will(
                         answer(
                                 new Answer1<Integer, Object[]>() {
@@ -681,7 +693,7 @@ public Integer answer(Object[] s) {
 
     @Test
     public void can_accept_non_vararg_answer_on_var_args_function() throws Exception {
-        given(iMethods.varargs(any()))
+        given(iMethods.varargs(any(String[].class)))
                 .will(
                         answer(
                                 new Answer2<Integer, String, String>() {
@@ -695,7 +707,7 @@ public Integer answer(String s1, String s2) {
 
     @Test
     public void should_work_with_var_args_with_no_elements() throws Exception {
-        given(iMethods.varargs(any()))
+        given(iMethods.varargs(any(String[].class)))
                 .will(
                         answer(
                                 new Answer1<Integer, String[]>() {
@@ -709,7 +721,7 @@ public Integer answer(String[] s) {
 
     @Test
     public void should_work_with_array_var_args() throws Exception {
-        given(iMethods.arrayVarargsMethod(any()))
+        given(iMethods.arrayVarargsMethod(any(String[][].class)))
                 .will(
                         answer(
                                 new Answer1<Integer, String[][]>() {