Runtime class instantiation in Actionscript 3.0

1 03 2007

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.

Advertisements

Actions

Information

38 responses

2 03 2007
Adam

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));

17 03 2007
Derek Wischusen

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

17 03 2007
Derek Wischusen

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

17 03 2007
24 07 2007
marsen

there is another easy solution.
var _class=getDefinitionByName(str) as Class

example:
//——————–
var mc=new (getDefinitionByName(str) as Class)()
addChild(mc)
//——————–

17 11 2007
Bob

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

2 03 2008
Kyle White

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!

2 03 2008
Kyle White


clObjectInstance['FunctionName'](); // also works.

Sorry for the two posts.. Just found this one out too 😉

26 05 2008
Mike

@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.

15 07 2008
Yui

var mc=new (getDefinitionByName(str) as Class)()
addChild(mc)

i was looking for this exact thing and this was the best solution i have found. many thanks 🙂

13 10 2008
Haden Pereira

Thanks man.. this is just what i was looking for. Spent an entire day looking for it.

21 10 2008
Software Pills » Forzar la carga de clases en Flex

[…] en la Red he encontrado varias soluciones como en https://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" […]

26 12 2008
ТгмТ

Very interesting article, I will wait for continuation

19 02 2009
Louise

Thank you so much for this post! I was pulling my hair out trying to get it to work.

22 03 2009
Sergey

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

26 03 2009
Sergey

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;

23 10 2009
Martin Zach

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

29 03 2009
David Turkel

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);

29 03 2009
David Turkel

Failed to show the import:

import FalseData.*;

Dave

29 03 2009
David Turkel

Never mind, please delete my comments. Didn’t go far enough w/ the debugger.

8 04 2009
19 04 2009
neopromo

Кто когда спать ложится? Я раньше часу двух ночи не ложусь.

19 04 2009
Tony

@neopromo – Ya nye panyemayu Ruskiye yezik

9 07 2009
David Parks

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?

4 10 2009
manu

Can anyone tell me how to create reference also dynamically. in my application iam generating the controls from an xml definiton dynamically

12 10 2009
Jasper

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
}

23 10 2009
Martin Zach

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);

23 10 2009
Martin Zach

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

23 10 2009
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

20 11 2009
vaishali

Thanks a Ton!!

Provided good clue reusing flex classes across swfs by invoking objects at runtime and avoid copypase of same class in different application.

20 11 2009
Николай

Компания Onix осуществляет проектирование сайтов любой сложности: корпоративные сайты. Web-дизайн, разработка фирменного стиля. Профессиональные решения для увеличения эффективности бизнеса. Так же выполняются следующие виды работ : разработка логотипа, раскрутка сайта, создание фирминого стиля и оптимизация и продвижение сайта

25 08 2010
Kawika

Thanks for the info! I was getting a terrible bug and the Flex compiler couldn’t find the class I knew for sure was in my SWC.

21 06 2011
nono

Otherwise, to get a asset in a class, assuming you have saved the loaded SWF into a variable within a class, you can do the following:

var AssetClass:Class = myClassWithLoadedResources.theLoadedSWF.loaderInfo.applicationDomain.getDefinition(‘path.to.the.Class’).AssetClass as Class;

var bitmap:Bitmap = new AssetClass();

21 06 2011
nono

Otherwise, to get a asset in a class, assuming you have saved the loaded SWF into a variable within a class, you can do the following:

var AssetClass:Class = myClassWithLoadedResources.theLoadedSWF.
loaderInfo.applicationDomain.getDefinition(“path.to.the.Class”).AssetClass as Class;

var bitmap:Bitmap = new AssetClass();

23 12 2011
Вам нужна интернет реклама в Донецке?

It?s actually a nice and useful piece of info. I?m glad that you simply shared this helpful info with us. Please stay us informed like this. Thank you for sharing.

28 07 2013
male psychology

I love your blog.. very nice colors & theme. Did you design this
website yourself or did you hire someone to do it for you?
Plz respond as I’m looking to create my own blog and would like to know where u got this from. many thanks

11 06 2014
emotional roleplay forum

Hi, I desire to subscribe for this webpage to get newest updates, thus where
can i do it please assist.

22 07 2014
ici

ici

Runtime class instantiation in Actionscript 3.0 | A Hill of Beans

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




%d bloggers like this: