August 2007 Archives

On [Transient], ObjectUtil.copy(), and Casting

| 1 Comment | No TrackBacks

I ran into an interesting situation not too long ago where ObjectUtil.copy wasn't working quite as I had expected. The solution that I came up with was to rely on [Transient] metadata. Confused? Let me explain...

ObjectUtil.copy is a wonderful utility method to perform a deep copy of an object. Its implementation is also amazingly simple:

var buffer:ByteArray = new ByteArray();
buffer.writeObject(value);
buffer.position = 0;
var result:Object = buffer.readObject();
return result;

Rather than using introspection and recursively copying properties from one object to another, the entire object is serialized into a array of bytes. When the bytes are deserialized, a brand new object is created copying all of the original contents.

Simple, but effective. Instead of writing a custom deep copy algorithm , the copy() method uses the built in Flash Player AMF capabilities. This is the same serialization that Flash Remoting uses. When you send an object to the server via Flash Remoting (<mx:RemoteObject/>), you send an AMF array of bytes describing the object that the server deserializes to create an identical object on the server.

Because of using AMF behind the scenes to perform object copies, a few interesting things happen:

  • If you try to cast the results of a copy to a class, the cast might fail.
  • Using the [Transient] metadata tag affects the output of copy().

When an object is deserialized from AMF, it does not automatically get created as a class instance. The object might have all of the properties of a class instance, but it will not be a true class instance unless the AMF packet includes type information about the object. The type information gets added to AMF in one of two ways:

If you're using [RemoteClass] metadata on a class instance being copied, then it is safe to cast the result as that particular class instance:

// The works if Book has [RemoteClass] metadata
var bookCopy:Book = Book( ObjectUtil.copy( book ) );

If you're not using [RemoteClass], before performing the copy you need to register the class against a string alias. The alias is written to the AMF packet so that when the object is deserialized, it can be created as the proper type. For example:

// Book doesn't have [RemoteClass] metadata, so associate the my.package.Book string
// with a reference to the Book class.
registerClassAlias( "my.package.Book", Book );

// Now we can cast the result of the copy without errors.
var bookCopy:Book = Book( ObjectUtil.copy( book ) );

So, what about [Transient], and how is this related to the issue I ran into where the copy wasn't working as I had expected? Now that you know how copy works behind the scenes, let's talk about [Transient].

The [Transient] metadata tag is not very well documented in Flex 2 or 2.0.1. If you look in some of the LiveCycle Data Services documentation you can see mentions of it, but there isn't a dedicated page on the subject. In the beta Flex 3 documentation, [Transient] is finally explained. There is also some documentation gathered on The Flex Non-Docs weblog.

Essentially, what it comes to is that using [Transient] on a property removes that property from the AMF packet during serialization. This is important. The reason [Transient] properties are not sent over the wire via Flash Remoting is because, again, they're not included in the AMF packet.

With the background information explained, onto the problem I ran into. Here's a small class that doesn't copy correctly (after the jump):



About this Archive

This page is an archive of entries from August 2007 listed from newest to oldest.

July 2007 is the previous archive.

September 2007 is the next archive.

Find recent content on the main index or look in the archives to find all content.

Archives

OpenID accepted here Learn more about OpenID
Powered by Movable Type 5.02