Java Generics WTF?!

Posted by    |      

Now here's something I didn't expect.

Linda was having some problems compiling code written with the new JPA 2.0 typesafe criteria API, and after looking into the problem, I really, really think this should compile.

The QueryBuilder interface defines the following method:

<Y extends Comparable<Y>> Predicate lessThan(Expression<? extends Y> x, Expression<? extends Y> y);

The compiler spits out an error in this case:

Expression<java.sql.Date> x = ....;
Expression<java.sql.Date> y = ....;
q.where( qb.lessThan(x, y) );

Why in hell? Substitute java.util.Date for Y, and all the bounds are satisfied:

  • java.sql.Date is a subtype of java.util.Date
  • java.util.Date is a subtype of Comparable<java.util.Date>

But apparently the compiler is refusing to consider the bound on Y when determining a candidate Y: it seems to decide from looking at just the parameter bounds that Y must be java.sql.Date, which does not implement Comparable<java.sql.Date>. To me this is just wrong and non-intuitive. Why not keep searching up the type hierarchy until you find something that matches?

So, there are two workarounds for this. The first is to explicitly tell the compiler what it should have been able to figure out for itself:

q.where( qb.<java.util.Date>lessThan(x, y) );

But a better solution is to redeclare the API as follows:

<Y extends Comparable<? super Y>> Predicate lessThan(Expression<? extends Y> x, Expression<? extends Y> y);

UPDATE: to see just how crazy this is, consider that the following does compile:

Expression<java.sql.Date> x = ....;
Expression<java.sql.Time> y = ....;
q.where( qb.lessThan(x, y) );

Back to top