YaK:: WebLog #535 Topic : 2007-06-30 03.00.21 matt : rant on java's generics | [Changes] [Calendar] [Search] [Index] [PhotoTags] |
[Back to weblog: pretention] |
A pair and I were debugging an InvalidCastException in the bowels of Hibernate a few months ago. We wrote this code after debugging in the depths of Hibernate, OGNL, and WebWork for a couple of days:
public class Model<T> { private T id; public void setId(T id) { if (typeIsStringArray(id)) { // HACK: this is a workaround for a bug where OGNL gets confused about generic types // search the web for 'webwork ognl generic types bug' for more info // Instead of the long, webwork gave us String[], whose first element is numeric this.id = (T)Long.valueOf(((String[])id)[0]); } else { this.id = id; } } //... }
The issue is that Java's implementation of Generics completely circumvents the type system by storing the parameterized type as Object. OGNL's reflection-based discovery only sees Object in the bytecode where T is used in the source code. OGNL sees Object and defaults to a String[], probably as a most general fallback that would map to most web controls. You would think you could lean on the compiler, but it doesn't help much. For instance:
List<Long> longs = new List<Long>(); List objects = (List)longs; List<String> strings = (List<String>)objects; strings.add("foo");
The compiler will give you a warning, but it will compile and then throw an exception. It's obvious in this example, but often the loss of the type-parameterization happens across library calls.
The bigger issue is that almost all of the Java frameworks favor Reflection instead of (semi-)static code generation. This makes sense, because code generation got a bad name due to suboptimal (read: really horrid) tools that were available at the time Java was introduced. Unfortunately, as you observed, Java's Generics circumventing the type system totally screws up many reflection-based frameworks. (This is aside from the fact that Java's reflection is very, very slow.)
In my opinion, Sun really shot themselves in the foot on this one. If they were looking to save their market share by having feature parity with C# 2.0, whose reflection is fast and Generics have a better implementation, they screwed up. If they were looking to not lose existing customers who had been screaming for Generics for 5+ years, they screwed up by bolting something onto the side just to have a surface-level feature parity.
By the way, you can't run Java 1.5 code on a 1.4 JVM, so the 'backward compatibility' argument, espoused by some of the Java/Sun apologists, is totally bogus.
Java 1.6 doesn't help these things. Here's hoping they get their act together for Java vNext before everyone but the die-hards jump ship to Ruby and C#. Thankfully, coding in C# 2.0 and Ruby in the evenings makes switching to Java during the day easier, knowing how much better things can be.
PS: Don't get me wrong, C# has some nooks and crannies that are really dumb also. They aren't fixed in C# 3.0, even. I'm hoping MS doesn't repeat Sun's mistake and just introduces some minor migration pains for the sake of cleaning up inconsistencies the language and the framework.
Discussion:showing all 0 messages |
(No messages) |
(last modified 2007-06-30) [Login] |