So, a few times now in the past few days I’ve come across someone that needed to instantiate a class in ActionScript knowing only the class’ name as a string. Here’s a description of how to do that.
In Java, it’s easy to get the reference to a class given a string of that class’ name, e.g. “com.acme.AClass”. I can say
String className = "com.acme.AClass";
Class clazz = Class.forName(className);
And I have a reference to a Class, which I can use to get an Object of that class. The only requirement is that I have that class available in the classpath. Does ActionScript have anything like Class.forName? Kind of. Here’s a simple example which actually instantiates the class:
import flash.utils.getDefinitionByName;
import com.acme.AClass;
...
var testObj:AClass;
var clazz:Class = Class(getDefinitionByName("com.acme.AClass"));
testObj = new clazz();
Why did I say “Kind of” above, then? As I mentioned, Java requires that the class is available in the classpath to be able to get a reference to it. ActionScript, however, requires that the Class be referenced in the code that calls getDefinitionByName(), or at least in the application that loads that code. That makes it a little harder to dynamically load and instantiate classes. It’s not enough that the class be imported, since that’s only a compile-time directive. The class must be referenced in the code explicitly, as in the line “var testObj:AClass” above. This sheds a little light on the notion of ActionScript’s “classpath”: Only classes referenced explicitly are compiled into the swf – so only those classes are available for runtime instantiation.
How do you get around that? What if you don’t know which classes you want to load while you’re developing? Well, there are some things I know you can do, and I’m sure there are some other routes available beyond those. One thing you could do is get a rough idea which classes you’ll need and, somewhere in your application, include and reference them all. This is the shotgun approach and it isn’t pretty. Another is to load a swf that you know references the classes you need. All that’s necessary is that the swf is loaded before getDefinitionByName is called. Watch this space for some other ideas, or post any approaches you’ve taken below.
Here’s another trcik to get the type of an object:
var o:Object; // some object of an unknown type
var clazz:Class = getDefinitionByName(getQualifiedClassName(o));
Hi Tony,
I’ve been playing around with this a lot lately. There is a third option that makes it possible to instantiate a class at runtime that you is NOT referenced anywhere in your application.
Here’s how:
1. put the classes that you want to instantiate at runtime in a Flex Library Project.
2. In the project for you application, add the .swc the library path.
3. In the compiler arguments for your application add -include-libraries
The -include-libraries compiler argument tells the compiler that you want to load all of the classes in the library, even the ones that are not referenced anywhere.
Once you’ve done this, you will be able to load any of the classes in the library at runtime.
One more trick:
If you go into the application that loads the library and create classes that have same name and namespace as the classes in your library project, the compiler will load the classes that are in your main application. This means that the library project only needs to contain empty classes that mirror the classes in your application that you want to instantiate at runtime.
WARNING: The tricks that I described seem to make Flex very unhappy. If you want to test them out I suggest that you use new projects in a new workspace.
- Derek
Part of my comment got cut out.
Step 3 should read:
3. In the compiler arguments for your application add -include-libraries path_to_swc
[...] Runtime class instantiation in Actionscript 3.0 [...]
there is another easy solution.
var _class=getDefinitionByName(str) as Class
example:
//——————–
var mc=new (getDefinitionByName(str) as Class)()
addChild(mc)
//——————–
I can’t get this to work, i only get:
(fdb) [Fault] exception, information=ReferenceError: Error #1065: Variable DynamicClassTest is not defined.
where DynamicClassTest is the class string
Great Article. One thing that should be noted here, is you can set properties via:
var clClass:Class = Class(getDefinitionByName("mynamespace.MyClass"));
var clTest = new clClass();
clTest['MyProperty'] = 200; // Notice the brackets, and the STRING property name
clTest.MyProperty++; // Obviously this always works too, but you may not always be able to statically code in things like this
trace(clTest['MyProperty'] == clTest.MyProperty); // Confirm the results
If you can only reference your objects using Strings, then setting/getting properties for the object(s) can only be done using the method outlined above. I feel this should probably have been addressed in the article. I for one would be implementing a method that not only uses variable classes from strings, but variable property setting as well.
Thanks for the article!
clObjectInstance['FunctionName'](); // also works.
Sorry for the two posts.. Just found this one out too
@adam, that’s not necessary, this is easier:
var clazz:Class = object;
Also neat is this (both work):
var test = new(String);
var test = new(getDefinitionByName(“String”))
The pleasures of dynamic languages.
i was looking for this exact thing and this was the best solution i have found. many thanks
Thanks man.. this is just what i was looking for. Spent an entire day looking for it.
[...] en la Red he encontrado varias soluciones como en http://thillerson.wordpress.com/2007/03/01/runtime-class-instantiation-in-actionscript-30/. Aquí se mencionan dos soluciones. Una consiste en utilizar en una variable "dummy" [...]
Very interesting article, I will wait for continuation
Thank you so much for this post! I was pulling my hair out trying to get it to work.
Hello
Please help me brothers. I wish to know how to get package name by class name in actionscript 3. For instance `
var className:String = ‘Sprite’;
var package:String = getPackage(className);
Is there such a technic?
Thanks in advance
Hello all
Does anybody know how to qualify a class name in actionscript 3 ? for instance:
var className:string = ‘myClass’;
var fullClassPaths:Array = getClassFullPath(className);
trace(fullClassPaths); // com.package_1::myClass, com.package_2::myClass;
Hi,
first of all thanks for this very good site!
To get the QualifiedClassName try this:
import flash.utils.getQualifiedClassName;
getQualifiedClassName(dg.columns[0].itemEditor.generator)
if the item editor was a textArea this is what would be returned – mx.controls::TextArea
Cheers!
Martin Zach
P.S: i got the solution from David, see
http://forums.adobe.com/message/2336185#2336185
I was trying to do this for the purpose of mocking response data for a demo. I had a set of static “Accounts” that would return back different data by using an overriden method. To get around the explicit reference, I simply put all of my dynamic classes in the same package of my project (“FalseData.Account1, FalseData.Account2, etc.).
In my class where I was doing reflection, I just imported using “*”. That did the trick.
public function FalseInvoke(accountNumber:String, serviceName:String):Object{
var result:Object = null;
var falseResult:FalseResult;
var className:String = “FalseData.Account”+accountNumber;
var ClassReference:Class = getDefinitionByName(className) as Class;
var instance:Object = new ClassReference();
var account:AccountData = instance as AccountData;
var rawResult:String = account["serviceName"]();
falseResult = new FalseResult(rawResult);
Failed to show the import:
import FalseData.*;
Dave
Never mind, please delete my comments. Didn’t go far enough w/ the debugger.
[...] you very much to http://thillerson.wordpress.com/2007/03/01/runtime-class-instantiation-in-actionscript-30/ for pointing me in the right [...]
Кто когда спать ложится? Я раньше часу двух ночи не ложусь.
@neopromo – Ya nye panyemayu Ruskiye yezik
One additional thing that would help complete this excellent article:
How do you also pass a variable list of parameters to the constructor of such a dynamic object?
Case in question: I want to instantiate a set of objects defined by an XML received from the server & add them to my scene. Some objects have no arguments for the constructor, but some do. The XML can easily pass in the required arguments as needed. But how do I dynamically pass these arguments to the constructor (as in an array). Such as can done with the myFunction.call(this, argsArray) method?
Something like this is what I need:
var mc=new (getDefinitionByName(str) as Class).call(thisNewThing, argsArray)
Any ideas?
Can anyone tell me how to create reference also dynamically. in my application iam generating the controls from an xml definiton dynamically
i didnt find a way to call the constructor of a class.
i use someting like this as workaround::
public var _arg0
public var _arg1
constructor( arg0 = null, arg1 = null ){
if(arg0) this.arg0 = arg0
if(arg1) this.arg1 = arg1
if(argsComplete()) instantiate()
}
public function instattiate(){
// instantiate
}
public function set arg0(v:*){
this._arg0 = v;
if(argsComplete()) instantiate()
}
public function set arg1(v:*){
this._arg1 = v;
if(argsComplete()) instantiate()
}
public function argsComplete():Boolean{
if(_arg0 && _arg1) return true els return false
}
Hi Jasper,
did you try this:
public class MyClass
{
import …
public var myInt:int=new int;
public function MyClass() // Same name as Class!!!
{
//super(); // calls a constructur of super class if any
this.myInt=myInt;
init();
}
public function init():void{
}
You can call the Constructor like this:
MyClass(500);
Hi,
similar sutuation with a property:
I know only the propertyName as a String.
Is there a way to access the property at runtime?
Cheers!
Martin Zach
Hi,
I haven’t tested it, but this seems to be the solution, see:
http://www.justskins.com/forums/dynamic-access-to-as-properties-reflection-16508.html
Cheers!
Martin Zach