Introduction

Flash is a lightweight cross-platform runtime for rich media, enterprise applications and mobile applications, as well as an integrated development environment. Flash can be programmed in ActionScript 1/2/3.

Tuesday, June 7th, 2005 at 4:35 pm

As2lib Reflection API

What are reflections? Is Flash supporting reflections? What functionalities is the As2lib Reflection API (org.as2lib.env.reflect) offering me and how can I use these functionalities?

Note that this article has also been published on the official as2lib homepage: As2lib Reflection API.

Reflection Basics

What are reflections? How do reflections help me with development? What other programming languages support reflections?

Reflections help you find out everything about your API at run-time; your API is reflected. For example the name of a class an instance was instantiated of or all methods declared by a class that match a given naming pattern. In theory there are nearly no bounds. In languages that support reflections by default, like Java or C#, it is even possible to find out about the parameters of methods and their types.

As I now already stated, the programming languages Java and C# have reflections support. The reflection mechanism of these languages is built-in. These reflection APIs are thus in some respects more powerful than the one I will present in this article.

The most common usage of reflections is to generate good string representations of objects. These string representations can then be used for logging and in error/detail messages. But you can also use reflections to map from a XML file, database or property file to an object. Another common usage is the creation of dynamic factories (GoF, Factory Design Pattern) that resolves classes by name at run-time or instantiates passed classes.

If you are an experienced ActionScript programmer you may have noticed that all these things are possible with a ‘little’ knowledge of ActionScript 1.0 and Flash right now; except finding out class, properties and methods names. But what is missing is a good API that accomplishes these tasks in a performant and save way. Performance is gained by caching results and by good algorithms, safety by comprehensive test suites, a well-typed API, good run-time checks and the assurance that everything works fine in Flash, Flex and with MTASC.

In case you have been hooked: go-on reading and step directly into the As2lib Reflection API.

The Reflection Utility

What is the light-weight reflection utility? What services does it offer? What are its advantages?

The As2lib Reflection API is split into two parts, a light-weight and a heavy-weight one. The light-weight part exists only of one class, the ReflectUtil. This class offers basic methods to look up names of types and methods and to find out whether a specific method is static (per class) or is a constructor.

Its advantages are:

  • It is light-weight. This means that the class has little dependencies and the SWF file size is thus only increased by a minimum.
  • Its usage is quite simple. You do not have to deal with multiple classes and instances, but only invoke static methods.
  • It is fast. Note that the heavy-weight part is also fast, but maybe a little slower because of more delegation. But this speed difference is really at a minimum.

Its disadvantages are:

  • It may not offer all needed functionalities.
  • It does not cache results.
  • It offers only a low-level API.
  • It is neither flexible nor extensible.

Depending on your needs this class may be all you need. The As2lib always uses this class internally to look up API names that are in most cases included in log or error messages.

The most common usage is to look up type names. You have two options: you can either get the type name directly for a class (this is a function in ActionScript) or for an instance of a class.

  1. import org.as2lib.env.reflect.ReflectUtil;
  2. import com.mydomain.myapplication.MyClass;
  3.  
  4. // traces the name of the class looked up by a class
  5. trace("By Class: " + ReflectUtil.getTypeName(MyClass));
  6.  
  7. // traces the name of the class looked up by an instance
  8. var myInstance:MyClass = new MyClass();
  9. trace("By Instance: " + ReflectUtil.getTypeName(myInstance));
  10.  

The output of the above code is:

  1. By Class: com.mydomain.myapplication.MyClass
  2. By Instance: com.mydomain.myapplication.MyClass

The same approach applies to looking up method names. You again have the option between using a class or an instance as basis. Note that either the class itself or any super-class must implement the searched for method. Note that the following example is not a real-life example but just a demonstration of the different ways of performing the wanted task.

  1. import org.as2lib.env.reflect.ReflectUtil;
  2. import com.mydomain.myapplication.MyClass;
  3.  
  4. // traces the name of the per class method looked up by class and method
  5.  
  6. trace("By Class: " + ReflectUtil.getMethodName(MyClass.myStaticMethod, MyClass));
  7.  
  8. // traces the name of the per instance method looked up by class and method
  9. trace("By Class: " + ReflectUtil.getMethodName(MyClass.prototype.myMethod, MyClass));
  10.  
  11. // traces the name of the per instance method looked up by instance and method
  12. var myInstance:MyClass = new MyClass();
  13. trace("By Instance: " + ReflectUtil.getMethodName(myInstance.myMethod, myInstance));

If you run the above code you get the following output:

  1. By Class: myStaticMethod
  2. By Class: myMethod
  3. By Instance: myMethod
  4.  

A futher important method is the “getTypeAndMethodInfo” method. This method returns all needed information about the type and the method. This is whether the method is static (per class), the fully qualified name of the type and the name of the method. You may wonder why not just using the available methods to fulfill all these tasks step-by-step. This would work, but it is slower and needs more method calls. Another more important issue is that the method may not be directly implemented by the passed type, but by its super-type. In such a case you’d want the type name to be the one that implements the method and not the passed one. All this is taken into account by this method, which makes it important to mention.

  1. import org.as2lib.env.reflect.ReflectUtil;
  2. import com.mydomain.myapplication.MyClass;
  3.  
  4. // gets the type and method information
  5. var info:Array = ReflectUtil.getTypeAndMethodInfo(MyClass, MyClass.myStaticMethod);
  6.  
  7. // if the method is static ‘info[0]’ is ‘true’ otherwise ‘false’
  8. var output:String = info[0] ? "static " : "";
  9.  
  10. // adds the fully qualified type name
  11. output += info[1];
  12.  
  13. // adds the method name
  14. output += "." + info[2] + "()";
  15.  
  16. // traces the output
  17. trace(output);

The output is:

  1. static com.mydomain.myapplication.MyClass.myStaticMethod()

If the method were not static and were implemented by a super-class the output would have looked something like this:

  1. com.mydomain.myapplication.MySuperClass.myMethod()

For the full-range of methods and their usage take a look at the API documentation. Now let’s go-on to the full-featured API.

The Class Info

How can I find out everything about a class? What methods and properties does it declare? What are its super-classes? What is its namespace and of which package is it a member of? How can I get all its methods and properties that match a given criteria?

When you use the As2lib Reflection API the first thing you need is in most cases a ClassInfo instance. Given this instance for a specific class you can perform almost all operations offered by the API related to your class. Note that the “ClassInfo” represents classes as well as interfaces because a differentiation is not possible at run-time. To get a “ClassInfo” instance for your specific class you need either the class itself, an instance of that class or the name of the class.

  1. import org.as2lib.env.reflect.ClassInfo;
  2. import com.mydomain.myapplication.MyClass;
  3.  
  4. // gets a class info by class
  5. var classInfoByClass:ClassInfo = ClassInfo.forClass(MyClass);
  6.  
  7. // gets a class info by instance
  8. var myInstance:MyClass = new MyClass();
  9. var classInfoByInstance:ClassInfo = ClassInfo.forInstance(myInstance);
  10.  
  11. // gets a class info by name
  12. var classInfoByName:ClassInfo = ClassInfo.forName("com.mydomain.myapplication.MyClass");
  13.  

All these class infos are functionaly the same, they are even the same instances; the only thing that differs is how they were obtained. Given such a class info instance you can get the following basic information.

  1. trace("The class’s name: " + classInfo.getName());
  2. trace("The class’s fully qualified name: " + classInfo.getFullName());
  3. trace("The super class’s fully qualified name: " + classInfo.getSuperType().getFullName());
  4. trace("The class’s namespace: " + classInfo.getPackage().getFullName());
  5. trace("The class’s constructor: " + classInfo.getConstructor());
  6. trace("The declared methods: " + classInfo.getMethods(true));
  7. trace("The declared properties: " + classInfo.getProperties(true));
  8.  

If you like to you can also create a new instance of the represented class.

  1. var newInstance:MyClass = classInfo.newInstance("arg1", 2);

To get a MethodInfo instance that represents a method of your class or any super-class you have the name of or the concrete method as function you can use the “ClassInfo.getMethod” method. Note that the following works totally the same for properties, but with a PropertyInfo and the “ClassInfo.getProperty” method.

  1. import org.as2lib.env.reflect.MethodInfo;
  2.  
  3. // gets a method info by name
  4. var methodInfoByName:MethodInfo = classInfo.getMethod("myMethod");
  5.  
  6. // gets a method info by concrete method
  7. var myInstance:MyClass = new MyClass();
  8. var concreteMethod:Function = myInstance.myMethod;
  9. var methodInfoByConcreteMethod:MethodInfo = classInfo.getMethod(concreteMethod);
  10.  

Now let us come to a little more complex method, the “ClassInfo.getMethods” method. In its simplest from, which I used in an example at the beginning, this method simply returns either only the methods declared by the class itself or this method and the one of all super-classes. But it is also possible to use your own filter criteria. You must therefore at first create a class that implements the TypeMemberFilter interface. You can then implement your filter criteria in the “filter” method that returns “true” if the passed-in type member shall be excluded/filtered or “false” if not. Let us say we want to filter all methods that do not start with the string “add”.

  1. import org.as2lib.env.reflect.TypeMemberFilter;
  2. import org.as2lib.env.reflect.TypeMemberInfo;
  3.  
  4. class MyMethodFilter implements TypeMemberFilter {
  5.  
  6.     public function TypeMemberFilter(Void) {
  7.     }
  8.  
  9.     public function filter(typeMember:TypeMemberInfo):Boolean {
  10.         if (typeMember.getName().indexOf("add") == 0) {
  11.             return false;
  12.         }
  13.         return true;
  14.     }
  15.  
  16.     public function filterSuperTypes(Void):Boolean {
  17.         return false;
  18.     }
  19. }
  20.  

You can now use an instance of the filter “MyFilter” as parameter for the “ClassInfo.getMethods” method to receive only methods that have the prefix “add”.

  1. var methods:Array = classInfo.getMethods(new MyMethodFilter());
  2.  

The above mechanism for methods works the same for properties. You only have to use the equivalent property methods. Take a look for these in the API documentation of the “ClassInfo” class.

The Package Info

How can I find out everything about a package? What members, classes and packages, does it have? What are its parent packages? How can I get all its members that match a given criteria?

As with class infos you can get PackageInfo instances either by a concrete package or by name.

  1. import org.as2lib.env.reflect.PackageInfo;
  2.  
  3. // gets a package info by concrete package
  4. var packageInfoByPackage:PackageInfo = PackageInfo.forPackage(com.mydomain.myapplication);
  5.  
  6. // gets a package info by name
  7. var packageInfoByName:PackageInfo = PackageInfo.forName("com.mydomain.myapplication");
  8.  

The two returned package infos are functionally and physically the same, they are the same instance. Given either of these instances you can find out the following basic information.

  1. trace("The package’s name: " + packageInfo.getName());
  2. trace("The package’s fully qualified name: " + packageInfo.getFullName());
  3. trace("The parent package’s name: " + packageInfo.getParent().getName());
  4. trace("Is this package a/the root package?: " + packageInfo.isRoot());
  5. trace("The package’s member classes: " + packageInfo.getMemberClasses());
  6. trace("The package’s member packages: " + packageInfo.getMemberPackages());

A specific member class or package can also be obtained either by concrete class or package or by name.

  1. import org.as2lib.env.reflect.ClassInfo;
  2. import com.mydomain.myapplication.MyClass;
  3.  
  4. // gets a class member by name
  5. var classMemberInfoByName:ClassInfo = packageInfo.getMemberClass("MyClass");
  6.  
  7. // gets a class member by concrete class
  8. var classMemberInfoByClass:ClassInfo = packageInfo.getMemberClass(MyClass);
  9.  
  10. // gets a package member by name
  11. var packageMemberInfoByName:PackageInfo = packageInfo.getMemberPackage("mymodule");
  12.  
  13. // gets a package member by concrete package
  14. var packageMemberInfoByPackage:PackageInfo = packageInfo.getMemberPackage(com.mydomain.myapplication.mymodule);
  15.  

In the previous article on class infos we talked about getting methods or properties that match a given criteria. This is also possible with package infos but the criteria must now be met by member classes and member packages. We do again need a filter that filters/excludes unwanted package members. This filter must implement the PackageMemberFilter interface. This time we want to include all abstract classes that start with the “Abstract” string to be included in the result; sub-packages shall also be searched through.

  1. import org.as2lib.env.reflect.PackageMemberFilter;
  2. import org.as2lib.env.reflect.PackageMemberInfo;
  3.  
  4. class MyClassMemberFilter implements PackageMemberFilter {
  5.  
  6.     public function PackageMemberFilter(Void) {
  7.     }   
  8.  
  9.     public function filter(packageMember:PackageMemberInfo):Boolean {
  10.         if (packageMember.getName().indexOf("Abstract") == 0) {
  11.             return false;
  12.         }
  13.         return true;
  14.     }
  15.  
  16.     public function filterSubPackages(Void):Boolean {
  17.         return false;
  18.     }
  19. }

We can now use our filter as follows:

  1. var classMemberInfos:Array = packageInfo.getMemberClasses(new MyClassMemberFilter());

Exactly the same mechanism can also be applied to member packages. Take a look at the API documentation of the “PackageInfo” class for the appropriate methods.

order generic viagra accutane online find cheap viagra buy generic soma price of clomid cialis online cheap viagra drug drug cialis buying generic viagra pharmacy cialis buy cheapest viagra purchase soma viagra cost order cialis viagra for sale buy cialis purchase synthroid online generic zithromax viagra overnight shipping cheapest viagra online cheapest zithromax cheap cialis tablet buy viagra from india acomplia prescription buy viagra no prescription required levitra pharmacy buying generic cialis buy zithromax without prescription lasix online viagra buy online zithromax without a prescription buy cialis from canada purchase viagra overnight delivery cialis for sale levitra online stores buy acomplia without prescription cheap generic levitra cheap propecia online cheap price viagra buy cheap viagra internet synthroid pharmacy viagra online cheap cialis uk cheap viagra from uk cheapest generic cialis online buy cialis in canada accutane pharmacy find cialis no prescription required order acomplia cheapest propecia price of acomplia buy generic cialis viagra in bangkok buy cheap propecia online buy lasix purchase levitra online find cheap viagra online buy discount viagra online clomid pharmacy clomid without a prescription buy generic acomplia soma prices cheapest soma buy zithromax lasix prescription viagra discount levitra without a prescription buy zithromax cheap acomplia pills cheap accutane cheap viagra overnight delivery soma buy viagra us