Friday, April 9, 2010

Type Coercion failed no more

We recently upgrade from Flex 3.2 to Flex 3.5, and ran into a slew of mysterious type coercion errors.
Type Coercion failed: cannot convert Object@... to com.mycompany.myapp.MyDto
Executive summary: if you have a loadable module that gets loaded, unloaded, reloaded, and you use RemoteClass for annotating DTO's for BlazeDS or LDS, then you're going to have some Type Coercion issues after the reload. In the preinitialize method of your module, you need to manually register your classes using registerClassAlias.

A bit of context about our application. First we load a generalized shell of a console, which can then loads within it one of many Modules that runs different applications. Depending on what the user does, different modules get loaded and unloaded at run-time.

Our module makes heavy use of BlazeDS for communication with the back-end Java server. The objects we were getting the type conversion errors on were always our DTO objects, which were marked with the RemoteClass metadata tag for serializing to/from the server with BlazeDS. And the error always seemed to happen during de-serialization.

Things always worked fine the first time the module was loaded. But if it got unloaded and re-loaded, then the Type Coercion errors would start happening.

Googling about the problem usually led us down the path of people having problems with multi-version applications, and the solutions were usually to put the definitions of your remote classes into the main .swf. We don't have a multi-version application (we load, unload, reload the same .swf), and we can't modify the main .swf (it's owned by another team. Anyways, it runs lots of apps and can't reasonably pull in our app specific classes).

So I got to thinking about the problem. We knew that when the module gets reloaded, it gets loaded into a new ApplicationDomain. For whatever reason, when messages get returned from the server back to the client, our best guess was that it was still building objects using the classes from the ApplicationDomain from the first load. The profile confirmed that the old classes were still loaded, and weren't being garbage collected, in spite of our best efforts.

RemoteClass was a bit mystical and magical, but StackOverflow has deeper magic. Discovering that all RemoteClass does is invoke registerClassAlias for you, it was reasonable to think that it wasn't working properly on the subsequent loads.

So a quick trial using registerClassAlias instead of RemoteClass, and the Type Coercion errors go away. Voila!