Sunday, February 24, 2013

Problem with ObjectUtil copy

We all have used this wonderful method copy() in ObjectUtil class. It does a deep copy of the object using the following lines of code:
public static function copy(value:Object):Object
    {
        var buffer:ByteArray = new ByteArray();
        buffer.writeObject(value);
        buffer.position = 0;
        var result:Object = buffer.readObject();
        return result;
    }

As the code implies it does not copy each and every property recursively but the object is serialized into a array of bytes which is then de-serialized to get a new object. It makes use of built in Flash player AMF capabilities and it is exactly the same serialization mechanism that is used for remoting. When we send an object using remoting we send an AMF array of bytes which is de-serialized at the other end. As AMF is used to copy few things happen:

1. If we try to cast the result of copy to a class it may fail. For example when I tried to use 'as' operator to cast the result it failed.
2. Also when we use transient metadata tag output gets affected.

When the object gets de-serialized it does not create an instance of the class automatically. The object may have all the properties but still not a true instance (rather an object of class Object or ObjectProxy) unless the AMF packet includes type information about the object. This information gets added to the packet in two ways:

1. If the remoting tag is used: [RemoteClass]
2. If the class is registered using registerClassAlias() method

If we use remoting tag then it is easy. For example:

//assume employee has [RemoteClass] metadata.
var employee:Employee = Employee (ObjectUtil.copy(emp));

We may not always have this tag. In one of my project I was having a class ProfileMetaData which was making use of various properties of other value objects and was not sent back to business layer. So there was no question of remoting. And as expected after copy() I was not able to cast the result. So we need to register the class against a string alias. For example:

registerClassAlias("com.app.vo.ProfileMetaData",ProfileMetaData);
//Now we can copy and caste
var profileCopy:ProfileMetaData = ProfileMetaData (ObjectUtil.copy (report) );

What about the transient? If a property is transient it gets removed from the AMF packet during serialization. The reason they are not sent over the network via Flash Remoting is because  they are not included in the AMF packet. So there is no question of reading them back. In some cases it is useful.

More:
http://archive.darronschall.com/weblog/2007/08/on-transient-objectutilcopy-and-casting.html
http://stackoverflow.com/questions/14576627/how-to-work-registerclassalias-method-for-custom-mxml-components

3 comments:

ADmin said...
This comment has been removed by a blog administrator.
mspecht said...

Really good explanation. It helped me to find the reason for a warning which I got when I tried to copy an object which contains a custom object as attribute.
registerClassAlias helped to get rid of the warning. Next problem was that the contained object had two parameters in its constructor. After replacing them with setter and getter it worked perfectly.

Akhil Mittal said...

Thanks mspecht.