7

There is a method in hamcrest library:

package org.hamcrest.core

...

public static <T> Matcher<T> allOf(Matcher<? super T> first, Matcher<? super T> second) {
    List<Matcher<? super T>> matchers = new ArrayList<Matcher<? super T>>(2);
    matchers.add(first);
    matchers.add(second);
    return allOf(matchers);
}

In my code, I call this method with first being Matcher<Object> and second being Matcher<SomeException>.

And now:

  • When I compile it with Eclipse with 1.6 target, it makes <T> Matcher<SomeException>.
  • When I compile it with javac 1.7 with 1.6 target, it makes <T> Matcher<SomeException>.
  • When I compile it with javac 1.6 with 1.6 target, it makes <T> Matcher<Object>

The question is, what <T> should be in such case?

My understanding is, that there is a bug in javac 1.6 and it should be Matcher<SomeException>, as this is a common type for input arguments (SomeException is a subtype of Object) and then, it is 100% sure, that returned Matcher will be Matcher<SomeException>.

Am I right? And is there any way to force javac 1.6 to behave properly?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Marcin
  • 4,080
  • 1
  • 27
  • 54

2 Answers2

3

The compiler will do an inference based on actual arguments. It will start out with the initial constraints of Matcher<Object> << Matcher<? super T> and Matcher<SomeException> << Matcher<? super T>. From that it will infer the constraints T << Object and T << SomeException. Object will be eliminated when the minimal erased candidate set is constructed. The remaining candidate SomeException will (eventually :D) be substituted for T.

So far we've shown eclipse and JDK7 behave correctly in this case. I don't think there is any way to force javac to behave correctly as well. You can either explicitly state the type argument or use JDK7 (specifying source and target to be 6).

Ben Schulz
  • 6,101
  • 1
  • 19
  • 15
1

There are two things you should consider:

  1. First you could use it like this: CoreMatcher.<SomeException>allOf(...) which would explicitly set T.

  2. Second, due to type-erasure, as run-time you ALWAYS have a Matcher<Object>. So in either case the run-time behavior is the same.

John B
  • 32,493
  • 6
  • 77
  • 98
  • Good catch with CoreMatcher, but it is CoreMatchers in my hamcrest :) Regarding the 2nd point - I know. I was able to compile with eclipse and run mvn test then. – Marcin Mar 07 '13 at 12:45