Flex/Flash/Actionscript

Sneaky Flex trick to get the name of any calling functions

Well I’ll be damned, in my last post I wrote about how I was trying to figure out which class was calling addEventListener on a FlexSprite. I couldn’t figure out a way to get the name of the calling class, or the name of the method that called addEventListener(). Well, Almog Kurtser commented that there’s a trick you can do by using the Error class and the getStackTraceMethod() to parse out these strings.

If you call: trace(new Error().getStackTrace()) you’ll get something that looks like:


Error
at MonkeyPatchTest/___MonkeyPatchTest_Application1_creationComplete()[path/to/source/src/MonkeyPatchTest.mxml:4]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()[E:\dev\flex_3_beta3\sdk\frameworks\projects\framework\src\mx\core\UIComponent.as:9041]
at mx.core::UIComponent/set initialized()[E:\dev\flex_3_beta3\sdk\frameworks\projects\framework\src\mx\core\UIComponent.as:1165]
at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\flex_3_beta3\sdk\frameworks\projects\framework\src\mx\managers\LayoutManager.as:696]
at Function/http://adobe.com/AS3/2006/builtin::apply()
at mx.core::UIComponent/callLaterDispatcher2()[E:\dev\flex_3_beta3\sdk\frameworks\projects\framework\src\mx\core\UIComponent.as:8450]
at mx.core::UIComponent/callLaterDispatcher()[E:\dev\flex_3_beta3\sdk\frameworks\projects\framework\src\mx\core\UIComponent.as:8393]

Within that long string you have all sorts of information about every calling function all the way up the stack. You can parse that all out and figure out where in the application you were. You can do this from anywhere in your app.

So I updated the monkey patched event dispatcher example in my last post to use this method and lo and behold we can get the class name of the class that called addEventListener(). We even get the method name and the line number where addEventListener was called.

Now in the FlexSpy example you get much more information and can trace back exactly where the event listener was added. Sweet! A big thanks goes to Almog (and to Alex Harui who Almog references as his source of this little gem).

IMPORTANT NOTE: The Error.getStackTrace() method only works with the DEBUG version of your swf. If you export a release build then a call to Error.getStackTrace() won’t work.

Related:

  • A while back Ben Clinkinbeard asked a question on flexcoders saying "Am I the only one who wishes EventDispatcher exposed its listeners?" The fundamental issue was that he wanted to get a list of all the event listeners that had been added to a given component. The approach: using FlexSprite…
    Tags: function, event, flexsprite, class, monkey, listener, flexspy, source, addeventlistener, called
  • Pretty sweet logo, whoever designed that must be pretty much the best person in the world. Get your 360|Flex stuff here. And if you haven't registered for 360Flex, do that here.
    Tags: flex, sweet
Standard

13 thoughts on “Sneaky Flex trick to get the name of any calling functions

  1. Pingback: dougmccune.com » Blog Archive » Monkey Patching FlexSprite to list all event listeners on any Flex component

  2. Pingback: Twitter Response from @axna « TweetTrack

  3. Although the documentation says getStackTrace() will return null if not using the debugger version of the player, that doesn’t mean that it will return null in a release build played in the debugger version of the player. The source information in the square brackets is missing, but the function names are still there. This version of functionName() works for me in either a debug or release build (current FB 3 beta):

    package
    {
    public function functionName():String
    {
    var s:String = new Error().getStackTrace();
    s = s.substring(s.indexOf(“at”) + 2);
    var i:int = s.indexOf(“at”) + 3;
    var j:int = s.indexOf(“()”, i);
    return s.substring(i, j);
    }
    }

  4. @Alan, hmm, interesting. All I know is that in my blog post I tried embedding a version of the app that I exported as a release build with FB 3 B3 and the getStackTrace() stuff didn’t work when I viewed it on the web page (maybe my player didn’t know it was supposd to be in debug mode?). So then I just re-uploaded the version that was the normal debug swf and it all worked fine for me.

  5. johannes says:

    as you have the debug player it should work. try on a virgin machine with the normal runtime.

    arguments.caller was very handy for event listener clean up in the past, pity tis gone when using anon functions with event listeners.

  6. Glenn Williams says:

    Hi,

    nice little trick.

    Is that a new version of flexSpy, or just one you’ve hacked together. I’ll like the source if you’re making it available.

    cheers
    glenn

  7. Hi,

    that’s really nice monkey you’ve got 🙂

    I think Theo and Johannes are right, mxmlc keeps the stack trace in both debug and release, it’s a matter of flash player version.
    I wasn’t aware of the verbose-stacktraces Theo blogged about.
    I guess maybe the reason they left that information in the release swf by default is to enable developers logging their apps.
    Hmm..and maybe not.

    Cheers,
    Almog Kurtser.

  8. JC says:

    Keep in mind that if you’re running the debugger, you can see the stack trace at any time within the Debug panel. What’s also nice is that if you’re on a breakpoint, you can click on any of the items in the stack in that panel to switch to that object’s context, ie: be able to see its variables and such. Very handy stuff.

  9. Pingback: The Error.getStackTrace() Smart Bug @ Bill White’s Blog

  10. Pingback: The getStackTrace Super Bug @ Bill White’s Blog

  11. Arodicus says:

    Great tip! Really saved my butt!

    Note: Alan Shaw’s example is great but has a flaw: If a class or method contains the letters “at” you’ll get bogus results.

    Corrected version:

    public function functionName():String
    {
    var result:String = “”;
    try {
    var stack:String = new Error().getStackTrace();
    var stackArray:Array = stack.split(“\n\tat”);
    var subStack:String = stackArray[3]; // because this is the 3rd function away from the caller… we want the caller
    var j:int = subStack.indexOf(“()”);
    result = subStack.substring(0, j+2);

    } catch(e) {}
    return result;
    }

Comments are closed.