Russell said:
I'm actually coming to agree with that conclusion, particularly since
from the page Knute linked to (thanks Knute!) I find it's possible to
suppress just the one type of warning for just the one method, which is
much cleaner than global suppression; so unless it turns out there's a
better way to do it, that's the solution I'm going with.
It turns out there's a better way to do it.
First generify Record:
public class Record<T extends Comparable<? super T>> {
private T inner;
...
private T get () { return inner; }
}
Next make your comparator:
public class RecordComparator<T> implements Comparator<Record<T>> {
public int compare (Record<T> x, Recort<T> y) {
return x.get().compareTo(y.get());
}
}
x.get() and y.get() are both T, and as T extends Comparable<? super T>,
the compareTo should work. It just requires that you can generify
Record. Of course you could just add a compareTo to the Record class and
have
public class Record<T, U extends Comparable<T>>
implements Comparable<Record<T, U>> {
private U inner;
...
private U get () { return inner; }
public int compareTo (Record<T, ? extends T> x) {
return get().compareTo(x.get());
}
}
Then you have U.compareTo(? extends T) being called on things that
implement Comparable<T> with U extending T. Should work.
The get method needn't return an "inner" private field; it can access a
database or what-have-you. Presumably that or future-proofing is the
reason for the get method instead of exposing the field.
(Future-proofing value is why this is good OO practise to begin with.)
If you can't control Record, you may be able to extend it. Or at least
wrap it:
public class MyRecord<T, U extends Comparable<T>>
implements Comparable<Record<T, U>> {
private Record inner;
MyRecord (Record x) { inner = x; }
... any other methods that thunk through to inner
@SuppressWarnings("unchecked")
private U get () { return (U)inner.get(); }
public int compareTo (Record<T, ? extends T> x) {
return get().compareTo(x.get());
}
}
Now that nasty, foul-smelling cast is encapsulated in a single method
call with a single evil, throbbing @SuppressWarnings("unchecked")
attached, and everything else can use the generic MyRecord, aside from
having to get an icky ungeneric Record to immediately quarantine inside
a new MyRecord from time to time. Just remember that it won't blow up if
you put the wrong Record in until you call get(). Put an assert(get()
instanceof whatever) after every constructor call and have your unit
tests watch for it to throw exceptions -- ClassCast *or* assertion failure.
If there's called code that really needs the original Record object, you
can implement a poison-seeping goo-oozing Record-returning getRecord()
method if you *really really have to* to pass to the older nongeneric
code. Just be sure to use the nifty Unicode-in-identifiers feature of
Java to put a glowing pentagram in the method name somewhere and locate
it at line 666 of the source file, mmmkay?