lodgvideon / hamcrest

Automatically exported from code.google.com/p/hamcrest
0 stars 0 forks source link

(Java) containsInAnyOrder incorrect generic type specification causes wrong method to have higher precedence #188

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
In Matchers.java:

  public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(T... items) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder(items);
  }

  public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(java.util.Collection<org.hamcrest.Matcher<? super T>> matchers) {
    return org.hamcrest.collection.IsIterableContainingInAnyOrder.<T>containsInAnyOrder(matchers);
  }

assume:

public class Widget { ... }

public class WidgetMatcher extends BaseMatcher<Widget> {

  public WidgetMatcher(Widget widget) {
    this.widget = widget;
  }

  ...

  public static WidgetMatcher widget(Widget widget) { ... }

  public static Collection<WidgetMatcher> widgets(Widget... widgets) {
    List<WidgetMatcher> widgetMatchers = new ArrayList<WidgetMatcher>();
    for (Widget widget : widgets) {
      widgetMatchers.add(new WidgetMatcher(widget));
    }
    return widgetMatchers;
  }    
}

If you then attempt to call:

containsInAnyOrder(widgetMatchers(widget1, widget2));

it calls containsInAnyOrder(T... items) rather than the Collection variant. I 
believe this is because the signature should be:

  public static <T> org.hamcrest.Matcher<java.lang.Iterable<? extends T>> containsInAnyOrder(java.util.Collection<? extends org.hamcrest.Matcher<? super T>> matchers) {

Java doesn't seem to allow any other "safe" way of calling this method other 
than using a naked generic type:

containsInAnyOrder((Collection) widgetMatchers(...))

Original issue reported on code.google.com by wshie...@google.com on 10 Aug 2012 at 2:06

GoogleCodeExporter commented 9 years ago

Original comment by t.denley on 16 Aug 2012 at 7:59

GoogleCodeExporter commented 9 years ago
+1

Same issue occurs on contains(). Trivial example:

            List<Matcher<Integer>> matchers = ImmutableList.of(
                equalTo(1)
            );

            assertThat(ImmutableList.of(1), contains(matchers));

Fails because it is calling the contains(Object...) method instead.

It is possible to work around it though:

            List<Matcher<? super Object>> matchers = ImmutableList.of(
                equalTo(1)
            );

            assertThat(ImmutableList.of(1), contains(matchers));

This works, but because I'm matching a List<Integer>, I don't get why I can't 
provide a List<Matcher<Integer>>.

Original comment by trejkaz on 4 Mar 2015 at 4:26