Creating custom Flex metadata tags for easier XML parsing
Having recently used Swiz for a project I became interested in learning more about custom metadata tags in Flex. I'm sure most Flex developers are familar with [Bindable], [Embed], [Event], plus a few others, but using Swiz you get introduced to a new tag, [Autowire]. Autowire ... where the heck did that come from, it's certainly not a standard Flex metadata tag. Being intrigued I decided to do some research and figure out how one would go about creating their own metadata tags and how they could be used.
My search for metadata enlightenment landed here:
http://www.quietlyscheming.com/blog/2007/10/24/declarative-binding-and-handlers-through-custom-metadata-flex-demo/
http://demo.quietlyscheming.com/MetadataExample/MetadataExample.html
http://demo.quietlyscheming.com/MetadataExample/MetadataExample.zip
Perfect, Ely's demo provides a good understanding of how one can create and utlize the metadata tags. The good news is they are relatively easy to create, the bad news is you can't do some of the special 'compiler magic' that tags like [Bindable] and [Embed] do.
The basic idea is you create any tag you want, you just need to tell the compiler to keep it and then using reflection provided by the describeType util you can see which public properties/methods have been annotated with the custom metadata tag.
So in 3 simple steps you can create your own metadata tag for use in Flex:
Step 1: in the compiler options you need to tell the compiler to keep your new metadata tag, using this -keep-as3-metadata+=XML. Be sure to use the '+=' otherwise you lose the standard Flex metadata tags. In this case I have added a tag XML.
Step 2: Add your new tag into your AS3/MXML files. Depending on how you intend to use your metadata tag, you may just have the tag, like this [XML] or with some attributes like this [XML(node="name", cdata="true")], just depends on how you intend to use it, totally your call.
Step 3: Create a class that uses the flash.utils.describeType to find the properties annotated with your shiny new metadata tag and then do whatever you want with it. The describeType util returns a XML object describing the public properties/methods on the specified class.
Great, so how about a real world example.
While reading up on how to create the custom metadata tags I came across a really good post by Christophe Coenraets on creating and using metadata tags. He created an AIR app that accesses a SQLLite database. Instead of manually mapping out the relationships between value objects and tables and the neccessary queries he used the metadata tags to annotate value object properties with their corresponding database table columns.
Christophe's sample gave me an idea on how to solve a problem that has bothered me for a long time, parsing XML into and out of value objects. Many of the projects I work on use REST services to pass XML data between a Flex client and the server. When the XML is received on the Flex side it needs to be converted into typed value objects in actionscript and correspondingly, when the data needs to be sent to the server, the value objects need to be converted into XML.
Normally this involves creating a setXML and getXML function on any value object. You end up with something like this:
public function setXML(xml:XML):void
{
id = xml.@id;
name = xml.name;
phone = xml.phone;
}
public function getXML():XML
{
var xml:XML = <person>
<name>{name}</name>
<phone>{phone}</phone>
</person>;
xml.@id = id;
return xml;
}
With only a few properties it's not bad, but adding more properites means having to update the setXML and getXML each time. It becomes tedious when creating many value objects.
Using custom Flex metadata tags you could easily remove the need for creating and managing all the code for xml reading and writing in any value object. The metadata tag would need to annotate each property with whether it is an XML node or attribute and what it's name should be.
Now the value object class looks like this:
package com.dgrigg.vo
{
import com.dgrigg.utils.XmlMetaParser;
[XML(node="person")]
public class PersonVO
{
[XML(attribute="id")]
public var id:int;
[XML(node="name", cdata="true")]
public var name:String;
[XML(node="phone")]
public var phone:String;
public function PersonVO()
{
}
public function setXML(xml:XML):void
{
XmlMetaParser.read(this, xml);
}
public function getXML():XML
{
return XmlMetaParser.write(this);
}
public function toString():String
{
return "[PersonVO id='" + id + "', name='"+ name +"', phone='"+ phone +"']";
}
}
}
You can see the getXML and setXML have now been reduced to one line each. The properties that I need to send and receive via XML have been annotated with a custom metadata tag [XML] and the class was also annotated to define what the root xml node name should be.
The XmlMetaParser class now does all the work of transposing data between xml and the value objects. At it's core the XmlMetaParser uses the flash.utils.describeType to retrieve the description of a class instance, including all metadata information. With that information it simply becomes a process of using the metadata info to read and write the data.
Using E4X you can quickly find the metadata nodes and values for each anotated property. A simple statement like this does the trick xml.variable.metadata.(@name=="XML").arg.(@key==key), where key is either 'node' or 'attribute'.
<variable name="id" type="int">
<metadata name="XML">
<arg key="attribute" value="id"/>
</metadata>
</variable>
<variable name="name" type="String">
<metadata name="XML">
<arg key="node" value="name"/>
<arg key="cdata" value="true"/>
</metadata>
</variable>
<variable name="phone" type="String">
<metadata name="XML">
<arg key="node" value="phone"/>
</metadata>
</variable>
As you can see, creating a custom Flex metadata tag is an easy process and it's uses are as limitless as using Flex to create something.
You can download the XmlMetaParser and sample files here.
Update 12/30/2009: the source code has been updated to handle complex objects, read more here.




Nov 09, 2009 at 6:07 AM
Very elegant solution, I like it!
But what if your VO has one or more VO's as a property?
Like:
PersonVO {
var address:AddressVO;
}
AddressVO {
var street:String;
var number:int;
var city:String;
}
Maybe declare a node as being "complex" and recurse the properties?
Nov 09, 2009 at 7:10 AM
Bart, yes that is a limitation of the current code. For my immediate needs it did not need deep recursion, however it is something I will likely get added in.
Dec 30, 2009 at 1:58 AM
Hi Derrick,
I haven't know that you can defined your own metatags, thats interessting.
I personally solve this xml to object problem different. I simply pass the xml to the constructor and retrieve and set the value upon the xml object like this;
Dec 30, 2009 at 11:43 AM
@mich passing arguments in the constructor is often not the best approach because you are tightly coupling object instantiation to a single 'method', in your case by passing it an xml value. What happens if you want to create an object without populating it with xml?
Dec 31, 2009 at 12:44 AM
yes, i agree with the constructor. you could do it also with a setXML method and instantiate an empty xml object in the constructor that you dont have a null pointer.
but i most cases these objects are specially made for your data loaded from the backend (simple dataholders) - at least in my apps ;), so they are created right after your backend data is loaded and then they are kind of flagged with this xml constructor to be created just there.