explorers' club

explorations in dev, science, sci-fi, games, and other fun stuff!

getDefinitionByName trick

27 Comments

I am in the process of working on a ClassUtil class that will have static methods for creating class instances from generic objects and xml objects. One thing that I use in order to create nested content within the outer-most object to be created is getDefinitionByName. If you are not familiar with this method check it out. It basically returns a Class object by provide the name of the class in a string format. You want a Class object of String, then you pass “String”. You want the Class object for com.somesite.model.vo.SomeVo, the you pass “com.somesite.model.vo.SomeVo” as the parameter and whallah! You just have to remember to use the fully qualified class path in the string parameter.

This technique combined with using describeType and others yields some pretty powerful results. More on that later tho. So the issue with using getDefinitionByName is that unless you have instantiated an instance of the class in question, your swf will contain the embedded class definition. Then you run into the run-time-error saying that the variable of that name cannot be found (or something like that).

The most common way to resolve this is to put a useless instance of the class somewhere in your application. Such as var foo:Foopher = null. Then the class definition of Foopher is embedded in the compiled swf. Someone please correct me if I am wrong in explaining this. The problem with this solution is it seems rather hacky. It just doesn’t settle well with me. So I sought a different path.

The more uncommon way to resolve this is to define your class with a static var like so:

package vo
{
import flash.net.registerClassAlias;
[RemoteClass(alias="vo.NestedObject")]
public class NestedObject {
static private var _isRegistered:Boolean = false;
public var id:uint;
public var name:String; public function NestedObject ()
{
if (!_isRegistered)
{
registerClassAlias("vo.NestedObject", NestedObject);
_isRegistered = true;
}
}
}
}

Now it may be that registerClassAlias is a bit expensive but seeing as it is done once and only once per class type, this shouldn’t pose a problem. The other benefit is that you don’t clutter unrelated classes or views with having to make dummy instances to get it to register. Lastly, you can pick and choose which classes to use this method on so as to limit the price of making the call.

Advertisements

27 thoughts on “getDefinitionByName trick

  1. Pingback: Twitter Response from @axna « TweetTrack

  2. This is actually how kuler.adobe.com works, using XML you can recreate the entire class object with nested children and even items in nested array that resolve to proper class.

  3. You don’t need to create an instance of a class to include it in the SWF, just reference the class by name (not through a string. Just having
    ClassName;
    is really all you need.

    What you described, though, reminded me of something I made a while back:
    http://www.senocular.com/?id=2.9

  4. @orboy (or senocular, is that you? if so I am honored by your presence here)

    Do you mean to say that all you have to do is include a ref to the class in the compiler options? I think I have read that you can do that, but I was opting for a more elegant solution in order to not have to include the class in any unnecessary places at compile time.

    I would love to understand the process in which by using registerClassAlias how it actually includes the class in the compiled swf. Or how any non-instantiated class makes its way into a compiled swf to be dynamically created at run-time.

  5. Thanks for the tip. What do you do if you have classes that extend this class? Seems like you may get into trouble there. Is just overwriting the constructor enough?

  6. Well considering these are Value Objects, you usually don’t extend them. That is not to say I never do that, as I have, but generally since VOs are treated as mere data objects with specified props, I usually don’t.

    But to answer the question, yes. The _isRegistered is a static prop so it would not be accessible to subclasses. You’d have to declare the constructor for the subclasses in order to register the proper value.

  7. I can’t seem to get this to work without first instantiating an object. I tried it and I still had to create an instance of my class before getting rid of the error you describe in your post. It looks like I can do it 1 of 2 things:

    1. put the following somewhere in my code.

    var vo:VO;

    2. or call the following before I try to create the object.

    flash.net.registerClassAlias(“com.company.vo.VO”,VO);

    Maybe I missed something in your example.

  8. send me an email with a zip of your source and will try it locally on my test app. jwopitz (at) gmail

  9. Thanks so much for posting this, it just saved my day!

  10. Pingback: [AS3] Force Class Import - Ultrashock Forums

  11. So … what’s the usage then? I too am running into the same problem as poorman – having to still include the dummy vars.

  12. Apparently, this code only work if you compile your swf with Flex, due to the [ ] syntax ([RemoteClass(alias=”vo.NestedObject”)])…

    If you compile the swf with the flash IDE, the [ ] call should’nt be considered.

    I had the same problem when I was trying to include fonts to the swf, without creating them in the library, but using the [] syntax, as described in the Colin Mook’s AS3 Book.

    Could anyone confirm or cancel this assumption?

    For those who can’t make the code working, are you devlopping with the Flash IDE?

    For those who can get the code working, are you devlopping with the flex builder/sdk?

    So far, the solution should be the found of a way to replace the [] call with an Flash IDE’s compiling option (if it exists!)…

    Does anybody know something about that?

  13. The project I’m building is not in Flex so
    I would really like to know if there is a way to accomplish this with just Flash (NOT flex).

    I use class names passed from an XML doc and use getDefinitionByName to use the strings as classes.

    So far I’ve created an (unused) array of all of the potential classes used which works but is really annoying ..

    If there is a way to use the registerClass trick with Flash can someone please let us know?

  14. Have you tried it in flash? The metadata tags, registerClass and getDefinitionByName are all basic as3, irrespective of your use of Flex. I have not tried it myself in Flash but I would assume it works in Flash as it does in Flex.

  15. Can someone give me a quick example of a no-frills way to call it? Using the initial NestedObject – quick and dirty on the timeline I’ve tried..

    import vo.*;
    import flash.utils.getDefinitionByName;
    //var uselessArray:Array =[NestedObject];

    var Klass:Class = getDefinitionByName(“vo.NestedObject”) as
    Class;

    // trace(getIt);
    new Klass();

    the only way it works is if I uncoment the
    uselessArray part

    Am I going about calling this class correctly?
    thanks –

  16. hi,

    i tried this in flash and it didn’t work.
    i think it is the same problem like embedding somezhing with the [Embed()]

  17. Hello,

    As you describe above, I’ve tried using registerClassAlias to assign a static variable in the class definition AS3 (not Flex), and I still get the error:

    ReferenceError: Error #1065: Variable MyClass is not defined.

    Having applied your method above, I was trying to do something like this:

    var dynClass:Class = Class(getDefinitionByName(“fully.qualified.MyClass”));
    var dynObj = new dynClass();
    addChild(dynObj);

    Could you show a usage example? Thanks

  18. I don’t quite understand how this works. You’re still pretty much explicitly defining the class you want to import. How is this any less work than doing the

    Box;

    trick ?

  19. Guys I figured out the perfect solution for my specific problem but I have a feeling you can tweak your code to behave in a similar way.

    var classNames:Array = [ClassA, ClassB, ClassC];
    var classInstances:Object = {};
    for each (className:Class in classNames) {
    classInstances.push(new className());
    }

    Hope that helps

  20. If I understand this correctly, we no longer have to import the to be created class in the creating class, only in the to be created class do we register it as an alias.

    So if we have A that we need to instantiate with getDefinitionByName(‘A’) and we do not want to import A, then in the definition of A we registerClassAlias(‘A’, A). Thereby we can use getDefinitionByName(‘A’) anywhere without first importing it.

    As far as I can tell, by using registerAlias, we are including the class in the running SWF, which only needs to happen once to be able to use getDefinitionByName.

    Hmm but this does bring up an interesting cat and mouse problem. If we need to first instantiate A to call registerAlias, then it would have already been imported, in which case we needn’t have registered it, because the class would need to be imported, loaded into the SWF, and instantiated somewhere for registerAlias to be called.

  21. Found this little trick that utilizes a metadata tag that compiles in classes for use with getDefinitionByName

    http://www.rozengain.com/blog/2009/08/21/getdefinitionbyname-referenceerror-and-the-frame-metadata-tag/

  22. I think something got missed in this thread, @orboy stated it a while back.

    But: you DO NOT need to instantiate the classes, the following would be sufficient.

    import package.*;

    private function classReferences():void
    {
    MyClass1;
    MyClass2;
    MyClass3;
    MyClass4;
    MyClass5;
    }

    The compiler will make the classes available in the SWF.

    • Of course, you can do away with the import altogether if you did…

      private function classReferences():void
      {
      package.MyClass1;
      package.MyClass2;
      package.MyClass3;
      package.MyClass4;
      package.MyClass5;
      }

  23. This is solved by selecting “Export Frame 1” in the properties of movieclip or sound!!! (In the library).

  24. Simply putting

    {
    MyClass1,
    MyClass2,
    MyClass3,
    MyClass4
    }

    in constructor of your main class does the trick

  25. I have a need for Flex utility that can create objects from a string representation. Sounds like you already started working on it. To clarify,given a string such as:

    “”

    I would like to have a utility that creates a BorderContainer and a Button inside of it.

    I’ve had some luck with getDefinitionByName as you mention. Can you tell me how far you got on this, any roadblocks you found, and if you have any code to share.

    Thanks so much.

  26. All the solutions provided to the getDefinitionByName() issue involves the name of the target class. In case that you are developing a module, that’s going to by use by another aplication who is only going to tell you the name (or adress) oh the class, and therefore, the module doesn’t know the class. The only thing it can count on is the complete name of the class. There are any solution???

    Sorry about my english

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s