13

JodaTime has

public final class DateTime extends BaseDateTime {...}

which works its way up to

public interface ReadableInstant extends Comparable<ReadableInstant>

Hamcrest has

public static <T extends java.lang.Comparable<T>> org.hamcrest.Matcher<? super T>
    greaterThan(T value) {...}

If I try

greaterThan(new DateTime());

then I get a compile error (Eclipse gives most clue)

The generic method greaterThan(T) of type Matchers is not applicable for the arguments (DateTime). The inferred type DateTime is not a valid substitute for the bounded parameter >

Am I right in thinking that the signature of greaterThan should actually be

public static <T extends java.lang.Comparable<? super T>> org.hamcrest.Matcher<? super T>     
    greaterThan(T value)

? And is there a way to fit these together short of casting to the raw Comparable?

Duncan McGregor
  • 17,665
  • 12
  • 64
  • 118
  • See also http://stackoverflow.com/questions/6452313/how-to-implement-a-generic-maxcomparable-a-comparable-b-function-in-java – Duncan McGregor Nov 01 '11 at 18:06
  • The [current source of `OrderingComparison`](http://code.google.com/p/hamcrest/source/browse/trunk/hamcrest-java/hamcrest-library/src/main/java/org/hamcrest/number/OrderingComparison.java) has `> Matcher greaterThan(T value)`. – David Harkness Nov 01 '11 at 18:17
  • @DavidHarkness - I should say that I was looking at 1.3.0RC1, but doesn't RC2 only change the return type? It's the argument that isn't accepted. – Duncan McGregor Nov 01 '11 at 18:26
  • Yes, the latest code seems like it wouldn't work with two different subclasses of a single parent class. – David Harkness Nov 01 '11 at 19:18

2 Answers2

16

Yes, it looks to me like that would be a better signature.

Have you tried specifying the comparison type explicitly?

Matchers.<ReadableInstant>greaterThan(new DateTime());

I don't believe you can call it using a static import and also specifying the type argument, unfortunately - but that may not be too much of hardship.

Of course an alternative is to cast the argument:

greaterThan((ReadableInstant) new DateTime());

I don't have Hamcrest handy, but the above worked fine for me using the signature you'd given me, in a test type.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

If you use it often and are bothered by the conversion, you can also implement your own Matcher like this:

public static Matcher<AbstractPartial> isAfter(final AbstractPartial partial) {
    return new BaseMatcher<AbstractPartial>(){

        @Override
        public void describeTo(final Description description) {
            description.appendText("after partial: ").appendValue(partial);
        }

        @Override
        public boolean matches(final Object object) {
            if (object instanceof AbstractPartial) {
                return ((LocalDate) object).isAfter(partial);
            }
            return false;
        }
    };
}

And test it like this:

    Set<LocalDate> dates = Sets.newHashSet(new LocalDate(2013, 1, 1), new LocalDate(2013, 1, 2), new LocalDate(
        2013, 1, 3));
    assertThat(
        CollectionUtils.isEqualCollection(filter(isAfter(new LocalDate(2013, 1, 1)), dates),
            Lists.newArrayList(new LocalDate(2013, 1, 2), new LocalDate(2013, 1, 3))), is(true));

If you want to use DateTime instead of LocalDate, just substitute AbstractPartial with AbstractInstant in the first listing.

Gismo Ranas
  • 6,043
  • 3
  • 27
  • 39