4

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.

mystarrocks
  • 4,040
  • 2
  • 36
  • 61
  • Provide explicit type arguments. – Sotirios Delimanolis Jan 07 '16 at 20:35
  • 1
    Maybe this helps [Checking that a List is not empty in Hamcrest](http://stackoverflow.com/questions/3631110/checking-that-a-list-is-not-empty-in-hamcrest) – Alexander Campos Jan 07 '16 at 20:41
  • 1
    Eclipse is *not* using the JDK compiler, it's using its own, so compiling with Eclipse running `1.7.0.79` is not the same as compiling with `javac` from JDK `1.7.0.79`. The Eclipse compiler may have better inference logic. – Andreas Jan 07 '16 at 20:44
  • @SotiriosDelimanolis obviously. I can't change the code now - I'm just trying to understand what's wrong here. – mystarrocks Jan 07 '16 at 20:49
  • @Andreas true. My maven build using the jdks 1.7.0.79 (and 1.6.0.31) works well though so it's not just a case of Eclipse using a more intelligent compiler. – mystarrocks Jan 07 '16 at 20:51
  • Could you possibly have two different versions of hamcrest on the classpath? That could cause indeterminism. IIRC that particular error should be fixed in 1.3. – K Erlandsson Jan 07 '16 at 20:51
  • @KErlandsson no. Besides, the `Matchers` was introduced only in 1.3. But yeah, there's no duplicate lib. – mystarrocks Jan 07 '16 at 20:54
  • @mystarrocks What do you mean with that `Matchers` was introduced in 1.3? I get your error when I run hamcrest 1.2 but not on 1.3. And the method signature for empty() had indeed changed to return a `Matcher>` instead of `Matcher>`. I would double check that only hamcrest 1.3 is acutally used when building on the system that fails. – K Erlandsson Jan 07 '16 at 21:01
  • @KErlandsson - I had the same suspicion, so I tried comparing the signatures of `empty` with previous versions of Hamcrest, but it looks like the `Matchers` class that contains the `is` and `empty` static methods were only introduced in Hamcrest 1.3. – mystarrocks Jan 07 '16 at 21:09

1 Answers1

1

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.

K Erlandsson
  • 13,408
  • 6
  • 51
  • 67
  • Argh, my bad maybe. I had the same suspicion as you did and I checked the code in the `GitHub` and the class was missing under `Hamcrest-library`, so I thought it was added in 1.3. Can you point me to the 1.2 source/javadoc that shows this method signature? – mystarrocks Jan 07 '16 at 21:11
  • @mystarrocks check for example GrepCode here: http://grepcode.com/file/repo1.maven.org/maven2/org.hamcrest/hamcrest-library/1.2.1/org/hamcrest/Matchers.java?av=f#395 – K Erlandsson Jan 07 '16 at 21:16
  • Thanks - a bit lazy of me to have missed to notice this. I'd expect multiple lib versions in the classpath to be the problem too although I haven't been able to confirm (yet). – mystarrocks Jan 07 '16 at 21:18
  • Awful - `hamcrest-all:jar:1.3` seems to have a dependency on `hamcrest-library:jar:1.2.1`. o_O – mystarrocks Jan 07 '16 at 21:35
  • @mystarrocks that sounds really weird. The version of `hamcrest-all:jar:1.3` I downloaded from Maven Central does not have any dependencies at all. – K Erlandsson Jan 07 '16 at 21:39
  • Apologies for the confusion - it's a transitive dependency of `com.jayway.jsonpath:json-path-assert:jar:0.8.1:test`. Thanks! – mystarrocks Jan 07 '16 at 21:43