I'm  sure that you've already used metadata tags in your flex applications. There are several reserved keywords like [Bindable], [Embed], [Event] and so on (the full list is available here). The function of the metadata tags is to provide additional information to the flex compiler. For example information about embeding assets, dispatching events. This article doesn't explain how to use the default flex tags (you can learn that from here). It shows you how to create your own metadata tags and how to use them.

First of all, to be able to use a custom tag you should inform the flex compiler about them. You can do that by adding a parameter to the additional compiler arguments like that:
-keep-as3-metadata+=NameOfTag1,NameOfTag2

Then you can write something like:
package {
   
    public class MyCustomClass {
       
        [NameOfTag1(myVar="test")]
        public var name:String;
       
        public function MyCustomClass() {
           
        }
    }
}

To use your tag's data you have to use flash.utils.describeType method. It returns a xml with information about your class. For example:
package lib.document {
   
    import flash.utils.describeType;

    public class MyCustomClass {
       
        [MyCustomTag(myVar="test")]
        public var name:String;
       
        public function MyCustomClass() {
            trace(describeType(MyCustomClass));
        }
    }
}

will return:
<type name="lib.document::MyCustomClass" base="Class" isDynamic="true" isFinal="true" isStatic="true">
    <extendsClass type="Class"/>
    <extendsClass type="Object"/>
    <accessor name="prototype" access="readonly" type="*" declaredBy="Class"/>
    <factory type="lib.document::MyCustomClass">
        <extendsClass type="Object"/>
        <variable name="name" type="String">
            <metadata name="MyCustomTag">
                <arg key="myVar" value="test"/>
            </metadata>
        </variable>
    </factory>
</type>

As you can see you have information about your metadata tag. You can use it to assign a value to your class's variable, to call a private method or something else.

The biggest problem in the usage of custom metadata is that you should add all your custom tags in the additional compiler arguments. If you have a lot of tags you should make a lot of changes in this direction. That's why I created a SWC component that will make your life easier. Just download the swc file from here and include it in your flex project. The idea is that the swc component is compiled with -keep-as3-metadata * argument, which means that if you include it in your project you can use tag with a name *. The swc file contains two classes:
  • com.krasimirtsonev.data.metadata.MetadataParser
    The purpose of this class is to fetch the xml that contains information about the metadata and composes objects by type MetadataVO
  • com.krasimirtsonev.data.metadata.MetadataVO
    Value object that contains structured data about every metadata tag

So, let's see a simple example of using these classes. We have a basic application class:
package lib.document {
   
    import mx.containers.Canvas;
   
    public class App extends Canvas {
               
        public function App() {
           
            var m:MyCustomClass = new MyCustomClass();
            trace("application name = " + m.name);
           
        }    
    }
}

It is really simple. We created an object by type MyCustomClass and printed a property name of this object. Here is the interesting part:
package lib.document {
   
    import flash.utils.describeType;
    import com.krasimirtsonev.data.metadata.MetadataParser;

    public class MyCustomClass {
       
        [*(doThisOperation="get-from-storage", parameterToTheOperation="name-of-the-app")]
        public var name:String = "";
       
        public function MyCustomClass() {
            MetadataParser.init(this, Analyser);
        }
    }
}

As you can see the property name of MyCustomClass is empty and basically we didn't put any data into it. But if you run the application will see:
application name = CUSTOM_METADATA_EXAMPLE

The CUSTOM_METADATA_EXAMPLE string comes from an additional class called Storage:
package lib.document {

    public class Storage {
       
        public static function getData(key:String):String {
            if(key == "name-of-the-app") {
                return "CUSTOM_METADATA_EXAMPLE";
            } else {
                return "missing key '" + key + "'";
            }
        }
    }
}

The Storage class has just one static method which returns that string if we pass a correct key (in our case this is name-of-the-app). The magic part is hidden in this line of code:
MetadataParser.init(this, Analyser);

The MetadataParser has only one method init which accepts two parametrs. The first one is your class (the class that contains the metadata) and the second one is class that will operate with your custom tags. Here is the content of my analyser:
package lib.document {
   
    import com.krasimirtsonev.data.metadata.MetadataVO;
   
    public class Analyser {
       
        public function Analyser(data:Array):void {
           
            var numOfVarData:int = data.length;
            for(var i:int=0; i<numOfVarData; i++) {
                var vo:MetadataVO = data[i] as MetadataVO;
                if(vo.metadata.doThisOperation == "get-from-storage") {
                    vo.classObj.name = Storage.getData(vo.metadata.parameterToTheOperation);
                }
            }
        }
    }
}

What happens is that the MetadataParser parses the metadata of MyCustomClass and converts it to an array of MetadataVO, which is passed to the constructor of our analyser. We can set as many attributes as we want and they will be available. In this current example I checked if the doThisOperation attribute has value of get-from-storage and if yes then I called the getData method of the Storage class with a key equal to the value of parameterToTheOperation attribute.
Here is the content of the MetadataVO class:
package com.krasimirtsonev.data.metadata {
   
    public class MetadataVO {
       
        public static const METADATA_FOR_CLASS:String = "MetadataForClass";
        public static const METADATA_FOR_VARIABLE:String = "MetadataForVariable";
        public static const METADATA_FOR_METHOD:String = "MetadataForMethod";
       
        public var xml:XML;
        public var classObj:*;
        public var metadata:Object = {};
        public var metadataFor:String = "";
        public var name:String = "";
        public var type:String = "";
        public var params:Array;
        public var declaredBy:String = "";
        public var returnType:String = "";
    }
}

  • xml - contains the xml representing the tag
  • classObj - reference to your class object. The one that calls MetadataParser.init. In most cases you will use it to access some public properties or methods.
  • metadata - an object that contains all the attributes of your metadata tag
  • metadataFor - string that shows where the tag is placed (i.e. before variable, method or class definition)
  • name - string that shows the name of the item after the tag (i.e. if you place the tag before variable with name myVar, this property will return myVar)
  • type - string that shows the type of the variable (if the tag is placed before variable)
  • params - if you place the tag before the method then this property returns information regarding the parameters of that method
  • declaredBy
  • returnType - string that shows the returned type of the method (if the tag is placed before the method)
And here is the code of the parser:
package com.krasimirtsonev.data.metadata {
   
    import flash.utils.getQualifiedClassName;
    import flash.utils.describeType;
    import flash.system.ApplicationDomain;
   
    public class MetadataParser {
       
        private static var _xml:XML;
        private static var _classObj:*;
       
        public static function init(classObj:*, Analizer:Class):void {
   
        _xml =
describeType(ApplicationDomain.currentDomain.getDefinition(getQualifiedClassName(classObj).replace("::",
".")));
            _classObj = classObj;
            var data:Array = [];
            data = data.concat(parse(_xml.factory.metadata.(|>@name == "*")));
            data = data.concat(parse(_xml.factory.variable.metadata.(|>@name == "*")));
            data = data.concat(parse(_xml.factory.method.metadata.(|>@name == "*")));
            new Analizer(data);
        }
       

        private static function parse(metadata:XMLList):Array {
            var data:Array = [];
            var vo:MetadataVO;
            var metadata:XMLList = metadata;    
            var metadataLength:int = metadata.length();
            for (var i:int=0; i<metadataLength; i++) {
                var args:XMLList = metadata[i].arg;
                var argsLength:int = args.length();
                switch (metadata[i].parent().name().toString()) {
                    case "factory":
                        vo = new MetadataVO();
                        vo.metadataFor = MetadataVO.METADATA_FOR_CLASS;
                        vo.xml = _xml;
                        vo.classObj = _classObj;
                        vo.metadata = {};
                        for(var j:int=0; j<argsLength; j++) {
                            vo.metadata[metadata[i].arg[j].@key.toString()] = metadata[i].arg[j].@value.toString();
                        }
                        data.push(vo);
                    break;
                    case "variable":
                        vo = new MetadataVO();
                        vo.metadataFor = MetadataVO.METADATA_FOR_VARIABLE;
                        vo.xml = _xml;
                        vo.classObj = _classObj;
                        vo.metadata = {};
                        for(j=0; j<argsLength; j++) {
                            vo.metadata[metadata[i].arg[j].@key.toString()] = metadata[i].arg[j].@value.toString();
                        }
                        vo.name = metadata[i].parent().@name.toString();
                        vo.type = metadata[i].parent().@type.toString();
                        data.push(vo);
                    break;
                    case "method":
                        vo = new MetadataVO();
                        vo.metadataFor = MetadataVO.METADATA_FOR_VARIABLE;
                        vo.xml = _xml;
                        vo.classObj = _classObj;
                        vo.metadata = {};
                        vo.name = metadata[i].parent().@name.toString();
                        vo.declaredBy = metadata[i].parent().@declaredBy.toString();
                        vo.returnType = metadata[i].parent().@returnType.toString();
                        for(j=0; j<argsLength; j++) {
                            vo.metadata[metadata[i].arg[j].@key.toString()] = metadata[i].arg[j].@value.toString();
                        }
                        var params:Array = [];
                        var paramsList:XMLList = metadata[i].parent().parameter;
                        var numOfParams:int = paramsList.length();
                        for(j=0; j<numOfParams; j++) {
                            params.push(
                                {
                                    index:metadata[i].parent().parameter[j].@index.toString(),
                                    type:metadata[i].parent().parameter[j].@type.toString(),
                                    optional:metadata[i].parent().parameter[j].@optional.toString()
                                }
                            );
                        }
                        vo.params = params;
                        data.push(vo);
                    break;
                }
            }
            return data;
        }
    }
}


As a conclusion I can say that by using the swc component you can parse your custom metadata in flex without adding anything to your compiler's path.

The source code of the example is available here.