Wednesday, February 4, 2009

Mission One

Maybe it's time to dust off the motorcycle helmet, boots, and gloves languishing in the garage and get that motorcycle license I was planning on two years ago...

Not that I have the spare change, or the spare time, and I do have a young daughter to consider, but wow. The world's fastest all-electric, from Mission Motors of San Francisco.


Back in the FDS (Flex Data Services) days we were stuck supporting Java 1.4.x. Hence, no enum support because they weren't available in the language until 1.5. But things changed awhile back when BlazeDS and LCDS up'ed their base supported JVM to 1.5.

However, just because we could now support enums in the JVM at the server didn't mean anything to the AVM (ActionScript Virtual Machine) at the client.

ActionScript (and ECMAScript) doesn't provide a native enum type. To complicate matters futher, the flash.utils.IExternalizable interface doesn't provide the writeReplace() and readResolve() hooks that the interface defines. When you're deserializing a raw byte stream into an object graph, you need a readResolve() in order to handle enums (singletons).

Java enum serialization can't be overridden at the server, which is good! It's good because this means that enums are always serialized and deserialized according to a consistent recipe. When they're serialized in Java-land (ignoring AMF for a moment), their String name value (as returned by the name() method) is all that's written to the byte stream. When they're deserialized, a single String value is read from the byte stream and passed to the enum's valueOf() method. The returned singleton instance is then readReplace()'ed into the resulting object graph.

Based on this behavior, BlazeDS and LCDS send Java enums to your Flex app as Strings. If the client needs to send an "enum" to the server, send the String value for the enum, and it'll be unpacked as the desired Java enum instance at the server.

But some folks want more than a simple String at the client. As I mentioned earlier, lack of native enum types in ActionScript coupled with lack of a readResolve() hook on flash.utils.IExternalizable makes this impossible. On top of that, when the Java enum instance is written to the AMF byte stream at the server, the AMF type prefix is for the native String type. That means the server-side type name for the enum isn't included in the byte stream so attempting to use registerClassAlias() or [RemoteClass(alias="...")] is futile (and you wouldn't want that anyways without a readResolve() hook at the client).

If you're deadset on representing these values as typed singleton instances at the client, you'd have to do something wacky like manually traversing the data returned from the server (i.e.: a RemoteObject result) and replacing your "enum" Strings or some other marker in the result with the corresponding client-side singleton type instance of your own making before anything else got its hands on the data. That's a lot of brittle data munging for very questionable payoff...

Perhaps at some happy point in the future we'll have a native enum type to work with at the client, but until then my recommendation is to take a deep breath, relax, and just work with Strings (along with defining matching String constants that you can use for data validation, assignments, and equality checks where it makes sense).