简体   繁体   中英

A strange generics edge case with Mockito.when() and generic type inference

I'm writing a test case that uses a java.beans.PropertyDescriptor using Mockito, and I want to mock the behavior of getPropertyType() to return an arbitrary Class<?> object (in my case, String.class ). Normally, I would do that by just invoking:

// we already did an "import static org.mockito.Mockito.*"
when(mockDescriptor.getPropertyType()).thenReturn(String.class);

However, oddly, this does not compile:

cannot find symbol method thenReturn(java.lang.Class<java.lang.String>)

But when I specify the type parameter instead of depending on inference:

Mockito.<Class<?>>when(mockDescriptor.getPropertyType()).thenReturn(String.class);

everything is hunky dory. Why can't the compiler correctly infer the return type of when() in this case? I have never had to specify the parameter before like that.

PropertyDescriptor#getPropertyType() returns an object of Class<?> , where the ? means "this is a type, but I don't know what it is". Let's call this type "X". So when(mockDescriptor.getPropertyType()) creates an OngoingStubbing<Class<X>> , whose method thenReturn(Class<X>) can only accept objects of Class<X> . But the compiler doesn't know what type this "X" is, so it will complain about you passing in a Class of any type. I think this is the same reason the compiler complains about calling add(...) on a Collection<?> .

When you explicitly specify Class<?> for the type on the when method, you're not saying that mockDescriptor.getPropertyType() returns a Class<?> , you're saying that when returns an OngoingStubbing<Class<?>> . Then, the compiler checks to make sure whatever you're passing into when is of a type that matches Class<?> ; since getPropertyType() returns the " Class<X> " I mentioned earlier, it of course matches the Class<?> you specified.

So basically

// the inferred type is Class<"some type">
Mockito.when(mockDescriptor.getPropertyType())

// the specified type is Class<"any type">
Mockito.<Class<?>>when(mockDescriptor.getPropertyType())

In my IDE, the error message for your original code is

The method thenReturn(Class<capture#1-of ?>) in the type OngoingStubbing<Class<capture#1-of ?>> is not applicable for the arguments (Class<String>)

That capture#1-of ? is the "X" I described above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM