ISanych ISanych - 24 days ago 8
Java Question

How type inference works in Java or why mockito even compile

Trying to fix method resolution in standalone java parser I found a code in mockito which I don't understand. And if I'm creating small test based on mockito code:

package org.mockitousage.matchers;

import java.util.Collection;

public class MoreMatchersTest {
public interface IMethods {
String simpleMethod(String argument);
String simpleMethod(Collection<?> collection);
String simpleMethod(Object argument);
}

private IMethods mock;

public static <T> T any() {
return null;
}

public static <T> T verify(T m) {
return m;
}

public void any_should_be_actual_alias_to_anyObject() {
verify(mock).simpleMethod(any());
}
}


I'm getting compilation error as I expect:

Error:(23, 21) java: reference to simpleMethod is ambiguous
both method simpleMethod(java.lang.String) in org.mockitousage.matchers.MoreMatchersTest.IMethods and method simpleMethod(java.util.Collection<?>) in org.mockitousage.matchers.MoreMatchersTest.IMethods match


But somehow mockito compiles successfully. Could you explain me please why code in mockito compiles (and which specialization of
<T>any
compiler choosing) or how to modify my sample so it will compile too (I understand that I could cast
any()
to specific type or remove overloads of
simpleMethod
but I want to be as close to mockito code as possible).

Command line output:

> javac -version
javac 1.8.0_111

> javac -d C:\w\MockitoTest\out\production\MockitoTest -classpath C:\w\MockitoTest\out\production\MockitoTest -sourcepath C:\w\MockitoTest\src -g -source 8 -target 8 C:\w\MockitoTest\src\org\mockitousage\matchers\MoreMatchersTest.java
C:\w\MockitoTest\src\org\mockitousage\matchers\MoreMatchersTest.java:23: error: reference to simpleMethod is ambiguous
verify(mock).simpleMethod(any());
^
both method simpleMethod(String) in IMethods and method simpleMethod(Collection<?>) in IMethods match
1 error

> javac -d C:\w\MockitoTest\out\production\MockitoTest -classpath C:\w\MockitoTest\out\production\MockitoTest -sourcepath C:\w\MockitoTest\src -g -source 7 -target 7 C:\w\MockitoTest\src\org\mockitousage\matchers\MoreMatchersTest.java
warning: [options] bootstrap class path not set in conjunction with -source 1.7
1 warning

Answer

So, to begin with the beginning, Java 8 defined type inference rules described in details here, so that some code that compiles happily under 1.7 or 1.6 doesn't compile any longer under 1.8, for instance the example code won't compile indeed:

public class MoreMatchersTest {
    public interface IMethods {
        String simpleMethod(String argument);
        String simpleMethod(Collection<?> collection);
        String simpleMethod(Object argument);
    }

    private IMethods mock;

    public static <T> T any() {
        return null;
    }

    public static <T> T verify(T m) {
        return m;
    }

    public void any_should_be_actual_alias_to_anyObject() {
        verify(mock).simpleMethod(any());
    }
}

There are multiple questions about that, see here and here for example.

So the question was why Mockito seemed to work, and the answer was rather simple. Mockito 2.x releases are compiled with targetCompatibility = 1.6 (github), and even Mockito on master uses language level 1.6 for some modules.