6

I am learning Hamcrest 1.3 and I want to come up with an example for each Hamcrest static method in Matchers. The Javadoc helpfully already has examples for some methods. I tested the following contains code snippet with Java 8 and it passed:

assertThat(Arrays.asList("foo", "bar"), 
           contains(Arrays.asList(equalTo("foo"), equalTo("bar"))));

However, my team is currently using Java 7 so I wanted to make sure all the examples work in that version. The above code snippet produces the following error in Java 7:

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

I know that Java 8 added new implicit typing features for static methods and I think this is likely related. I have attempted to refactor out parameters and casting them to the expected arguments, but that results in the same error:

List<String> actual = Arrays.asList("foo", "bar");
List<Matcher<String>> expected = Arrays.asList(equalTo("foo"), 
                                               equalTo("bar"));
assertThat(actual, contains(expected));

What is the proper way to call static <E> Matcher<java.lang.Iterable<? extends E>> contains(java.util.List<Matcher<? super E>> itemMatchers) in Java 7?

BennyMcBenBen
  • 1,438
  • 2
  • 20
  • 37
  • From what it looks like the compiler error is unrelated to type inference, and is instead something about the method having the incorrect number of arguments... – awksp Jun 10 '14 at 04:19

2 Answers2

10

In the Hamcrest Javadoc, the method signature for the contains() that you're targeting is:

 public static <E> Matcher<Iterable<? extends E>> contains(List<Matcher<? super E>> itemMatchers);

The important bit to note in the above signature is the List<Matcher<? super E>>. Java 7 cannot infer List<Matcher<? super E>> from List<Matcher<String>>. The contains() is additionally overloaded, so the signature of the method that Java 7 targets is:

public static <E> Matcher<Iterable<? extends E>> contains(E... items);

And this is the reason you're getting the cryptic compilation error message!

Fortunately, the fix is pretty straightforward:

List<String> actual = Arrays.asList("foo", "bar");
List<Matcher<? super String>> expected = Arrays.<Matcher<? super String>>asList(equalTo("foo"), 
                                                                                equalTo("bar"));
assertThat(actual, contains(expected));
Muel
  • 4,309
  • 1
  • 23
  • 32
  • Does adding the explicit type parameter `` to the `contains` call also fix the typing? It seems like that would force the compiler to pick the correct variant of `contains`. – DaoWen Jun 10 '14 at 12:38
  • @DaoWen Unfortunately not, the compiler will still select the `contains(E... items)` variant instead of the desired `contains(List> items)`. – Muel Jun 12 '14 at 00:03
  • 1
    Using `hasItem` instead of `contains` seems to help avoid the problem while maintaining readability. – Jan Molak Mar 10 '16 at 11:09
0

I don't have the libraries installed to readily test this, but I think this is a subtyping problem.

  • expected has type List<Matcher<String>>
  • contains(expected) has type Matcher<Iterable<String>>
  • actual has type List<String>
  • assertThat needs a first argument of type T and a second of type Matcher<T>
  • Your T is List<String>, which means it expects the second argument of type Matcher<List<String>>, not Matcher<Iterable<String>>.

I'm guessing this should fix it:

Iterable<String> actual = Arrays.asList("foo", "bar");
List<Matcher<String>> expected = Arrays.asList(equalTo("foo"), 
                                               equalTo("bar"));
assertThat(actual, contains(expected));

Again, I haven't tested this fix—but that seems like it would clear up the type issues.

DaoWen
  • 32,589
  • 6
  • 74
  • 101