2

I have an established pattern for lazy loading data from a server via AMF.

    private var _XeventDispatched:Boolean;
    private var _X:ArrayCollection;
    public function get X():ArrayCollection{
        if(!_XeventDispatched && (_X==null || _X.length==0)){
            var evt:Event = new Event();//whatever event is need for this data member
            dispatcher.dispatchEvent(evt);
            _XeventDispatched = true;
        }
        return _X;
    }
    public function set X(ac:ArrayCollection):void{
        return _X;
    }

This way the data is not loaded from the server until it is needed. (I'm using the Mate framework by the way, so when a UI is instanciated, and the injectors fire, they call this get method in the data manager class.)

What I'd like to do is create some kind of Metadata tag, similar to [Bindable] that will add the above methods in place of a public property.

[LazyLoaded(eventName="com.myCompany.LoadX")]
public var X:ArrayCollection;

Does the compiler have any hooks for this type of extension? It would save a lot of boiler plate code that is hard to read.

SuperSaiyen
  • 1,410
  • 10
  • 12

3 Answers3

2

As Flextra's has mentioned, one option is to use runtime reflection of the Metadata, and build your framework around this.

That's similar to how Lazy Loading is implented in dpHibernate (a Flex Lazy Loading framework which I'm a developer on). Specifically to get access to the getters and setters and intercept them with hooks for lazy loading, we make use of the [Managed] metatag, and tweak it's behaviour, which gets the compiler to build the hooks in for you.

It's a bit of a hack, but it may help you. (And we've built a pretty successful framework on top of that hack).

Alternatively, you can write your own compiler extensions which use your Metadata, and performs AST modifications to generate that code for you. However, it's not for the faint-of-heart.

Although the hooks for these extensions have been around for many years now, there's very little out there about how to do it, and you'd need to work it out by looking through the existing source.

Luckily, the boffin's at Adobe have been eating their own dogfood with regards to the compiler extensions, and a few of the Flex 4 features (such as Skinning) has been implemented as compiler extenions, giving you a few more examples to work from.

The source for the compiler is available here.. It may pay to take a look at the code for the Managed extension as a good starting point.

Alternatively, take a look at the SkinPart extension, HostComponent extension or [Embed] (which Clement Wong - the original developer of the compiler - once mentioned as the best starting point in understanding compiler extensions).

Marty Pitt
  • 28,822
  • 36
  • 122
  • 195
0

I think you want to use the keep--as3-metadata compiler argument. Something like this:

keep-as3-metadata+=LazyLoaded

JeffryHouser
  • 39,401
  • 4
  • 38
  • 59
  • I want to replace the public var with the lazy loaded methods similar to how a [Bindable] var gets replaced with its getters/setters at compile time. – SuperSaiyen Sep 28 '11 at 16:24
  • Oh, the only thing that will do is save your metadata in the compiled SWC. Most framework creators perform such actions at runtime based on their custom metadata. There is a way to drill down into the component to find the metadata and other info. If you want to change the way the Flex Compiler works, in order to generate different code based on that metadata, you're going to have to change the Flex Compiler. It is doable, since you can get the source. I wouldn't call it practical, though. – JeffryHouser Sep 28 '11 at 16:29
  • Thanks, i was hoping it had some kind of "hook" but i understand what you're saying, this application needs to be done pre-compile, not runtime. – SuperSaiyen Sep 28 '11 at 16:35
  • 1
    @SuperSaiyen Your best is using some ANT Script or other build tool that can parse code, look for that metadata and make the appropriate conversion before compiling it. – JeffryHouser Sep 28 '11 at 16:45
0

+1 Marty you lead me to this, but its different from your solution.

I've created a base class (BaseDataManager) that all other Mate data managers can extend from, and in that class I've added the below code:

        private var eventsDispatched:Array = new Array();
        protected function lazyLoad(value:*, eventType:String):*{
            if(!eventsDispatched[event] && (value==null || (value is IList && IList(value).length==0))){

                var clazzName:String = eventType.substr(0, eventType.indexOf(":"));
                var eventClazz:Class = Class(getDefinitionByName(clazzName));
                var event:Event = new eventClazz(eventType);

                dispatcher.dispatchEvent(event);
                eventsDispatched[event] = true;
            }
            return value;
        }

Then within each data manager, if the property is to be lazy loaded, this is their accessors:

    private var _X:ArrayCollection;
    public function get X():ArrayCollection{
        return lazyLoad(_X, XLoadEvent.LOAD_EVENT_TYPE);
    }
    public function set X(value:ArrayCollection):void{
        _X = value;
    }

This way most of the ugly, hard to read code is hidden away from the dev, yet still accessible for debugging if any problems were to arise.

SuperSaiyen
  • 1,410
  • 10
  • 12