Hi Magnus,
This looks pretty good to me.
I hope, Joe gave some insight for Comparable's.
Thanks,
Serguei
On 4/16/20 05:47, Magnus Ihse Bursie wrote:
This is the final part of removing all warnings from the build of
jdk.hotspot.agent. This patch includes a number of non-trivial fixes
for the few remaining unchecked warnings.
The good news is that with this fix (and after the recent removal of
Nashorn and rmic), the JDK build is finally complete free from
warnings for the first time ever! EPIC!!!!!1!!! :-)
The bad news is that this patch is probably the most complex of all
I've posted so far. :-/
I'll break down the changes in four groups:
* ConstMethod superclass issue
ConstMethod current extends VMObject. However, it is treated as a
Metadata (Metadata is a subtype of VMObject). For instance, this code
appears in Metadata.java:
metadataConstructor.addMapping("ConstMethod", ConstMethod.class);
I believe it is just an oversight that ConstMethod does not also
extend Metadata like the rest of the classes added to the
metadataConstructor mapping, one which has not been caught without the
extra type safety given by generics.
* ProfileData casting
In several places, a ProfileData item is extracted from a collection,
its type checked with instanceof, and then acted on accordingly.
(Yeah, nice and clean OOP abstraction at work! :-))
This works well most of the time, but when casting to ReceiverTypeData
or CallTypeDataInterface, the type include generic parametrisation, so
it needs to be cast to e.g. ReceiverTypeData<ciKlass,ciMethod>.
Unfortunately, this cannot be verified using instanceof, due to
generic type erasure, and thus the compiler considers this an
unchecked cast. (At least, this is my understanding of what is
happening.) As far as I can tell, this is legitimate code, and the
only way to really handle this (barring a more extensive rewrite) is
to disable the warning for these cases.
* Generification of the InstanceConstructor hierarchy
I have properly generified the InstanceConstructor hierarchy, with the
VirtualConstructor, StaticBaseConstructor and VirtualBaseConstructor
subclasses. (And also the related helper class VMObjectFactory.)
Most of it turned out OK (and with improved type safety), but there
was one piece of code that is a bit unfortunate. In
VirtualBaseConstructor, we have the following:
@SuppressWarnings("unchecked")
Class<? extends T> lookedUpClass = (Class<? extends
T>)Class.forName(packageName + "." + superType.getName());
c = lookedUpClass;
That is, we send in a name for a class and assumes that it will
resolve to a subtype of T, but there is no way to enforce this with
type safety. I have verified all current callers to the constructor so
that they all abide to this rule (of course, otherwise the code would
not have worked, but I checked it anyway). The alternative to
suppressing the warning is to redesign the entire API, so we do not
send in a class name, but instead a Class<? extends T>, and use that
to extract the name instead. At this point, I don't find it worth it.
This is, after all, no worse than it was before.
* SortableTableModel and TableModelComparator
This one was quite messy. The tables are being used in quite different
ways in different places, which made it hard to generify in a good
way. A lot of it revolves around keeping the data as Objects and
casting it to a known type. (Some of this behavior comes from the fact
that they extend old Swing classes which does this.) I've tried to
tighten it up as much as possible by introducing increased type safety
by generification, but in the end, it was not fully possible to do
without a major surgery of the entire class structure. As above, most
of it turned out OK, but not all.
The tricky one here is the helper TableModelComparator. This one took
me a while to wrap my head around. It implements Comparator, but the
compare() method takes "rows" from the model, which are just expressed
as Objects, and left to subclasses to define differently. For one of
the subclasses it uses the type T that the TableModel is created
around, but in other it uses an independent domain model. :-/ Anyway.
The compare() method then extracts data for the individual columns of
each row using the method getValueForColumn(), and compare them
pairwise. This data from the rows are supposed to implement Comparable.
In the end, I think I got it pretty OK, but I'm still an apprentice
when it comes to generics black magic. The subclasses of
TableModelComparator want to return different objects from
getValueForColumn() for different columns in the row, like Long or
String. They are all Comparable, but String is Comparable<String> and
Long is Comparable<Long>. So I needed to specify the abstract method
as returning Comparable<?>, since Comparable<String> is not
Comparable<Object>.
But then, for reasons that I do not fully fathom, I could not specify
Comparable<?> o1 = getValueForColumn(row1, columns[i]);
Comparable<?> o2 = getValueForColumn(row2, columns[i]);
int result = o1.compareTo(o2);
because the compiler did not accept the call to compareTo().
I did try to sacrifice a black rooster at midnight and walking
backwards in a circle three time, to no avail. Maybe the problem was
that it was not full moon or that I have no cat. In the end, I casted
o1 and o2 to Comparable<Object> and suppressed the warning for that cast.
If anyone knows what rituals I need to perform to make this work, or
-- even better -- how to fix the code properly, please let me know!
Bug: https://bugs.openjdk.java.net/browse/JDK-8242943
WebRev:
http://cr.openjdk.java.net/~ihse/JDK-8242943-SA-final-unchecked-warnings/webrev.01
/Magnus