mystarrocks
mystarrocks

Reputation: 4088

Hamcrest assertThat - type inference

Here's a simplified version of what's being done in one of my projects:

List<String> names = ...
assertThat(names, is(empty()));

This works just fine on my Eclipse running on Java 1.7.0.79 (and on 1.6.0.31).

However the compilation fails on a remote system that uses Java 1.7.0.55 (and 1.6.0.29) and here's the error message:

no suitable method found for assertThat(java.util.List<String>,org.hamcrest.Matcher<java.util.Collection<java.lang.Object>>)
    method org.hamcrest.MatcherAssert.<T>assertThat(T,org.hamcrest.Matcher<? super T>) is not applicable
      (actual argument org.hamcrest.Matcher<java.util.Collection<java.lang.Object>> cannot be converted to org.hamcrest.Matcher<? super java.util.List<String>> by method invocation conversion)
    method org.hamcrest.MatcherAssert.<T>assertThat(java.lang.String,T,org.hamcrest.Matcher<? super T>) is not applicable
      (cannot instantiate from arguments because actual and formal argument lists differ in length)
    method org.hamcrest.MatcherAssert.assertThat(java.lang.String,boolean) is not applicable
      (actual argument java.util.List<String> cannot be converted to java.lang.String by method invocation conversion)

I expect the first overloaded variant to match my case, but it doesn't due to a seemingly iffy type inference. Why does the compiler seem to think that the actual argument is of type org.hamcrest.Matcher<java.util.Collection<java.lang.Object>> when it clearly should be org.hamcrest.Matcher<java.util.Collection<? extends java.lang.Object>> knowing the signatures of is and empty methods.

The problem is that I have limited control over what JDK I can switch to on the remote system and this being a prod. test code, I am not allowed to workaround this either. So, at the moment what I'm trying to do is just understand if the problem is due to a buggy type inference on the said JDKs. Admittedly, I haven't tried the same on the said JDKs on my personal computer yet.

I use hamcrest 1.3 BTW.

Upvotes: 4

Views: 1872

Answers (1)

K Erlandsson
K Erlandsson

Reputation: 13696

It seems Hamcrest 1.2 is used when building on the system that fails. When I build your code with Hamcrest 1.2 it fails with the same error message while it works with 1.3. Checking the Hamcrest code, the Matchers.empty() signature has changed in 1.3 from:

public static <E> org.hamcrest.Matcher<java.util.Collection<E>> empty() // 1.2

to

public static <E> org.hamcrest.Matcher<java.util.Collection<? extends E>> empty() // 1.3

which would explain why it fails on 1.2 but works on 1.3.

You should check your project setup and the setup of the system that fails to ensure that only hamcrest 1.3 is on the classpath when building.

Upvotes: 1

Related Questions