Generics Hell - How do I pass a joda.DateTime to Hamcrest Matcher.greaterThan?
Question
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
?
Solution
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.
OTHER TIPS
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.