I’ve talked about AMF serialization size before, but there’s one tip I left out. Today’s article shows you one crucial step you need to take to make sure your AMF data is packed as tightly as possible so you’re not wasting file size or bandwidth.

Astute readers may have actually spotted today’s trick hidden and unmentioned in AMF Serialization Tricks. It has to do with the flash.net.registerClassAlias function that controls the name of your class objects when serialized to AMF, such as with ByteArray.writeObject. If you don’t call registerClassAlias at all, then all of your objects will be written out without a class name as the AMF equivalent of a plain Object. For example:

var bytes:ByteArray = new ByteArray();
bytes.writeObject(new MyClass());

This usually isn’t the desired option since one of AMF’s major features is its ability to give you nicely typed objects when you ultimately deserialize your AMF data via a function like ByteArray.readObject. So, you call registerClassAlias like so:

package com.mycompany.geom
{
    public class Parallelepiped {}
}
 
registerClassAlias("com.mycompany.geom.Parallelepiped", Parallelepiped);
 
var bytes:ByteArray = new ByteArray();
bytes.writeObject(new Parallelepiped());

Now you’ve successfully stored your object with its fully-qualified class name. The package name and the class name are stored, so you don’t have to worry about conflicts when two classes in different packages share the same name.

But there is a problem with this: the whole class name is stored in the AMF data. This fully-qualified class name is quite long and adds quite a lot of overhead. Fortunately, there’s no rule that the string you pass to registerClassAlias has to be the fully-qualified class name. You can take shortcuts here and use only as many characters as you need. Usually, you just need one:

package com.mycompany.geom
{
    public class Parallelepiped {}
}
 
registerClassAlias("P", Parallelepiped);
 
var bytes:ByteArray = new ByteArray();
bytes.writeObject(new Parallelepiped());

In this version only a “P” is stored as the class name. While this would be a terrible class name in the AS3 code, it’s only used for AMF serialization and deserialization so the rest of your code is unaffected. You don’t have to rename your classes. It’s not particularly obvious when trying to guess what the AMF data’s contents are, but this is often less important than minimizing the AMF data’s size. One idea is to use a “key” or “legend” of mappings from fully-qualified class name to AMF alias. You might even do this in your code where you have all your registerClassAlias calls. Or you could externalize it to another file with the rest of your app’s documentation.

Given these downsides, what kind of upsides can we expect in the form of AMF data size reductions? Here’s a sample app to find out:

package net.somebody.foo.goo.utils
{
	public class SomeClassWithAReallyReallyLongName
	{
		public var i:int;
		public var s:String;
		public var b:Boolean;
		public var n:Number;
	}
}
package
{
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.net.registerClassAlias;
	import flash.utils.ByteArray;
 
	import net.somebody.foo.goo.utils.SomeClassWithAReallyReallyLongName;
 
	public class AMFSize extends Sprite
	{
		private var logger:TextField = new TextField();
		private function row(...cols): void
		{
			logger.appendText(cols.join(",")+"\n");
		}
 
		public function AMFSize()
		{
			logger.autoSize = TextFieldAutoSize.LEFT;
			addChild(logger);
 
			row("Class Name", "Size");
 
			var plainBytes:ByteArray = new ByteArray();
			plainBytes.writeObject(new SomeClassWithAReallyReallyLongName());
			row("{Plain}", plainBytes.length);
 
			registerClassAlias(
				"net.somebody.foo.goo.utils.SomeClassWithAReallyReallyLongName",
				SomeClassWithAReallyReallyLongName
			);
 
			var longBytes:ByteArray = new ByteArray();
			longBytes.writeObject(new SomeClassWithAReallyReallyLongName());
			row("SomeClassWithAReallyReallyLongName", longBytes.length);
 
			registerClassAlias("C", SomeClassWithAReallyReallyLongName);
 
			var shortBytes:ByteArray = new ByteArray();
			shortBytes.writeObject(new SomeClassWithAReallyReallyLongName());
			row("C", shortBytes.length);
		}
	}
}

And here are the results:

Class Name Size
{Plain} 24
SomeClassWithAReallyReallyLongName 85
C 25

AMF Serialization Size

So with just one simple change from a long fully-qualified class name to a single character the total AMF size drops from 85 bytes to 24. While 61 bytes isn’t a big deal, it adds up when storing more objects and more types of objects in a more complicated serialization. If you’re using fully-qualified class names in your project’s AMF serialization, try switching to single characters and measure the results for yourself. It just might be an easy savings to bandwidth or file size.

Spot a bug? Have a question or suggestion? Post a comment!