Introduction

Based on the emit API as3commons-bytecode also offers a proxy API that allows for runtime dynamic proxy generation.
Dynamic proxies can offer a basic AOP interception mechanism, a proxy class is nothing more than a subclass of a class whose member invocations need to be intercepted.
This subclass is injected with a so-called method invocation interceptor, in as3commons-bytecode this interceptor is described in the IMethodInvocationInteceptor interface.
Now the constructor or any method or accessor can be overridden in this subclass and its arguments and/or return value can be intercepted and delegated to any number of IInterceptor instances.
So, in practice this would mean something like this, imagine this method:

public function returnMyName():String {
	return "John Doe";
}

In the dynamic proxy class this method would be overriden like this:

public function returnMyName():String {
	return methodInvocationInterceptor(this, InvocationKind.METHOD, "returnMyName", null, super.returnMyName);
}

As3commons-bytecode offers a simple implementation of the IMethodInvocationInteceptor interface which is injected by default.
This implementation is called BasicMethodInvocationInterceptor and holds an array of IInterceptor instances which will be invoked each time that the returnMyName() method is invoked.

To intercept the returnMyName() and change its return value, an IInterceptor implementation could look like this:

public class MethodInterceptor implements IInterceptor {

	public function TestMethodInterceptor() {
		super();
	}

	public function intercept(invocation:IMethodInvocation):void {
		if (invocation.kind === InvocationKind.METHOD) {
			invocation.proceed = false;
			invocation.returnValue = "Lady Gaga";
		}
	}
}

The BasicMethodInvocationInterceptor wraps all the necessary information in an IMethodInvocation instance and passes it on to the IInterceptor.intercept() method.

Setting the proceed property on the IMethodInvocation to false will prevent the original method in the proxied class from being invoked, and in this case to be replaced by the value returned by this IInterceptor implementation.

This example is of course rather pointless, but real-world scenarios that might benefit from this approach include cross-cutting concerns such as logging, security, validation, caching and transactions.

Interception works on constructors, methods and accessors that have have a public, protected or custom namespace scope. Setting proceed to false while intercepting a constructor will not prevent the super constructor from being invoked though. It is, however, of course possible to intercept and change the constructor's arguments.

Now, this is all nice and sweet, but how does this all come together in practice? In the following sections the various steps for generating proxy classes and injecting interceptors is explained.

Getting started

The generation of dynamic proxy classes relies on the bytecode based reflection. This is because, unfortunately, information such as the value of optional arguments is not available through regular reflection but is necessary to correctly create a valid subclass.

So, before using the proxy API be sure to populate the ByteCodeType cache:

var _applicationDomain:ApplicationDomain = FlexGlobals.topLevelApplication.loaderInfo.applicationDomain;
ByteCodeType.fromLoader(FlexGlobals.topLevelApplication.loaderInfo);
Do note that we keep a reference to the loaderInfo's ApplicationDomain property, this reference is very important for the proxy generation.
The ByteCodeType parsing will cache type information by ApplicationDomain, that way different definitions loaded into separate ApplicationDomains can be cached. However, ApplicationDomain.currentDomain will always return a new reference to an ApplicationDomain instance. So, be sure to hoist the loaderInfo.applicationDomain reference and pass that one into the defineProxy() methods later on. Otherwise the library will not be able to locate the necessary ByteCodeType data and will throw a ProxyBuildError.

For more information on bytecode based reflection visit the Bytecode reflection section.

Defining proxies

The main entry point for runtime dynamic proxy generation is the IProxyFactory interface.
To make use of this create an instance of the ProxyFactory class:

var proxyFactory:IProxyFactory = new ProxyFactory();

Now, to define a proxy for a specified class invoke the defineProxy() method:

var classProxyInfo:IClassProxyInfo = proxyFactory.defineProxy(MyClass, null, _applicationDomain);

This method returns an IClassProxyInfo instance which allows further definition of the proxy.
Its also possible to ignore the IClassProxyInfo instance entirely, in which case every public, protected and custom namespace scoped member on the specified class will be proxied. (Bytecode reflection is used here to obtain the information).

Should this not be desirable these methods will define specific members for proxying:

classProxyInfo.proxyMethod("myMethod");
classProxyInfo.proxyAccessor("myAccessor");

To have only methods of a certain scope proxied use the proxyMethodScopes property:

classProxyInfo.proxyMethodScopes = ProxyScope.PUBLIC;

The same mechanism can be used for accessor scopes:

classProxyInfo.proxyAccessorScopes = ProxyScope.ALL;

If only methods or accessors of a certain namespace need to be proxied, use the proxyMethodNamespaces and proxyAccessorNamespaces properties, which both can receive an Array of namespace URIs:

classProxyInfo.proxyMethodNamespaces = ["http://www.mydomain.com/mymethodnamespace"];
classProxyInfo.proxyAccessorNamespaces = ["http://www.mydomain.com/myaccessornamespace"];

If the original class is not dynamic, but its desired to have a dynamic proxy, set the makeDynamic property:

classProxyInfo.makeDynamic = true;

This is the equivalent for setting the dynamic keyword on a class definition:

public dynamic MyClass { /**/ }

(Of course, when the original class is already marked as dynamic this will override the makeDynamic value.)

Interface proxies

It is possible to create a proxy for an interface as well. In this case a Class that inherits from Object is created that implements the specified interface.

This functionality makes the most sense in a mocking scenario.

Generating the proxy classes

Once the proxy definitions have been completed it is time to generate the actual classes for those proxies:

var abcBuilder:IAbcBuilder = proxyFactory.generateProxyClasses();

The generateProxyClasses() method returns the IAbcBuilder that has been populated by the IProxyFactory enabling further modification and augmentation of the generated classes. Consult the emit documentation for more information on this.

Intercepting a class builder

To intercept the creation of a specific proxy class add an event listener for the ProxyFactoryBuildEvent.AFTER_PROXY_BUILD event, the instance of this event contains a reference to the IClassBuilder that is used to generate the specified class:

proxyFactory.addEventListener(ProxyFactoryBuildEvent.AFTER_PROXY_BUILD, afterProxyBuilderHandler);

function afterProxyBuilderHandler(event:ProxyFactoryBuildEvent):void {
	var clazz:Class = event.proxiedClass;
	var builder:IClassBuilder = event.classBuilder;
	/* further logic ommited... */
}

Intercepting the constructor method body creation

The ProxyFactoryBuildEvent.BEFORE_CONSTRUCTOR_BODY_BUILD event enables a developer to completely override the constructor method body creation.
Add a listener for the specified event and use the ProxyFactoryBuildEvent.methodBuilder property to modify the ICtorBuilder instance.

proxyFactory.addEventListener(ProxyFactoryBuildEvent.BEFORE_CONSTRUCTOR_BODY_BUILD, beforeConstructorBuildHandler);

function beforeConstructorBuildHandler(event:ProxyFactoryBuildEvent):void {
	var builder:ICtorBuilder = event.methodBuilder as ICtorBuilder;
	/* further logic ommited... */
}

Intercepting method body creation

The ProxyFactoryBuildEvent.BEFORE_METHOD_BODY_BUILD event enables a developer to completely override method body creation.
Add a listener for the specified event and use the ProxyFactoryBuildEvent.methodBuilder property to modify the IMethodBuilder instance.

proxyFactory.addEventListener(ProxyFactoryBuildEvent.BEFORE_METHOD_BODY_BUILD, beforeMethodBuildHandler);

function beforeMethodBuildHandler(event:ProxyFactoryBuildEvent):void {
	var builder:IMethodBuilder = event.methodBuilder;
	/* further logic ommited... */
}

Intercepting accessor body creation

The ProxyFactoryBuildEvent.BEFORE_GETTER_BODY_BUILD and ProxyFactoryBuildEvent.BEFORE_SETTER_BODY_BUILD events enable a developer to completely override accessor body creation.
Add a listener for the specified events and use the ProxyFactoryBuildEvent.methodBuilder property to modify the IMethodBuilder instance.

proxyFactory.addEventListener(ProxyFactoryBuildEvent.BEFORE_GETTER_BODY_BUILD, beforeGetterBuildHandler);

function beforeGetterBuildHandler(event:ProxyFactoryBuildEvent):void {
	var builder:IMethodBuilder = event.methodBuilder;
	/* further logic ommited... */
}

Loading the proxy classes into the AVM

When the proxy classes have been generated and customized the last step is to load the proxy classes into the AVM.

This process is asynchronous so the steps to take are as follows:

proxyFactory.addEventListener(Event.COMPLETE, handleLoaded);
proxyFactory.addEventListener(IOErrorEvent.VERIFY_ERROR, handleVerifyError);
proxyFactory.loadProxyClasses();

function handleLoaded(event:Event):void {
	//classes loaded successfully
}

function handleVerifyError(event:IOErrorEvent):void {
	//something went terribly wrong during class generation...
}

To load the proxy classes into their own ApplicationDomain, pass the specified domain to the loadProxyClasses()method, by default ApplicationDomain.currentDomain will be used:

proxyFactory.loadProxyClasses(new ApplicationDomain(ApplicationDomain.currentDomain));

Instantiating a proxy class

At this moment the IProxyFactory is ready to create proxy instances.

An IProxyFactory instance also functions as the classs factory for proxy instances.
To do this invoke the IProxyFactory.createProxy() method like this:

var instance:MyClass = proxyFactory.createProxy(MyClass, ["someVar"]) as MyClass;

Now, at this point, by default, the IProxyFactory has created a BasicMethodInvocationInterceptor instance and injected it as a constructor argument into the proxy instance.

In itself this is pretty useless since no IIinterceptors have been registered with the BasicMethodInvocationInterceptor.

In practice its therefore easier to defer the creation of the BasicMethodInvocationInterceptor (or any other IMethodInvocationInterceptor instance) to an event handler. This can be achieved by listening for the ProxyFactoryEvent.GET_METHOD_INVOCATION_INTERCEPTOR event:

proxyFactory.addEventListener(ProxyFactoryEvent.GET_METHOD_INVOCATION_INTERCEPTOR, getMethodInterceptor);

function getMethodInterceptor(event:ProxyFactoryEvent):void {
	var interceptor:BasicMethodInvocationInterceptor = new event.methodInvocationInterceptorClass() as BasicMethodInvocationInterceptor;
	interceptor.interceptors[interceptor.interceptors.length] = new MyInterceptor();
	event.methodInvocationInterceptor = interceptor;
}

Another way to delegate the creation of an IMethodInvocationInterceptor is to assign an IFactory instance to the IClassProxyInfo instance returned by the defineProxy() method:

var classProxyInfo:IClassProxyInfo = proxyFactory.defineProxy(MyClass, null, _applicationDomain);
classProxyInfo.interceptorFactory = new MyInterceptorFactory();

public class MyInterceptorFactory:IFactory {

	public function MyInterceptorFactory() {
		super();
	}

	public function newInstance():* {
		var interceptor:BasicMethodInvocationInterceptor = new BasicMethodInvocationInterceptor();
		interceptor.interceptors[interceptor.interceptors.length] = new MyInterceptor();
		return interceptor;
	}
}

A practical example

Lastly, to create a better picture, here is a complete example of the practical use of a proxy.

First of all, let's take this class, an object containing some kind of business logic:

public class MyBusinessObject {
	
	public function MyBusinessObject() {
		super();
	}
	
	public function calculateTotalPrice(order:Order):Number {
		/** actual logic ommitted **/
	}
}

Now imagine that the instantiation of this class and invocation of the calculateTotalPrice() method needs to be traced.

Its possible to write a simple IIinterceptor implementation that does this:

public class TracingInterceptor implements IInterceptor {
	
	public function TracingInterceptor() {
		super();
	}
	
	public function intercept(invocation:IMethodInvocation):void {
		switch(invocation.kind){
			case InvocationKind.CONSTRUCTOR:
				trace("{0} was instantiated", invocation.targetInstance);
				break;
			case InvocationKind.METHOD:
				trace("{0} was invoked with parameter {0}", invocation.targetMember, invocation.arguments[0]);
				break;
		}
	}
}

Now this code remains to wire everything together:

var proxyFactory:IProxyFactory = new ProxyFactory();
//Note: we don't use the IClassProxyInfo instance returned by the defineProxy method
//since we want all members (one method in this case) to be proxied:
proxyFactory.defineProxy(TracingInterceptor, BasicMethodInvocationInterceptor, _applicationDomain);
proxyFactory.generateProxyClasses();
proxyFactory.addEventListener(Event.COMPLETE, proxiesLoadedHandler);
proxyFactory.loadProxyClasses();

function proxiesLoadedHandler(event:Event):void {
	var proxyFactory:IProxyFactory = (event.target as IProxyFactory);
	proxyFactory.addEventListener(ProxyFactoryEvent.GET_METHOD_INVOCATION_INTERCEPTOR, createMethodInterceptor);
	var myBusinessObj:MyBusinessObject = proxyFactory.createProxy(MyBusinessObject) as MyBusinessObject;
	//This will yield a trace something like this: 'Sun Dec 26 17:43:19 GMT+0100 2010 DEBUG - MyBusinessObject was instantiated'
	myBusinessObj.calculateTotalPrice(new Order());
	//And this will yield a trace like this: 'Sun Dec 26 17:43:19 GMT+0100 2010 DEBUG - calculateOrderPrice was invoked with parameter Order'
}

function createMethodInterceptor(event:ProxyFactoryEvent):void {
	var interceptor:BasicMethodInvocationInterceptor = new event.methodInvocationInterceptorClass() as BasicMethodInvocationInterceptor;
	interceptor.interceptors[interceptor.interceptors.length] = new TracingInterceptor();
	event.methodInvocationInterceptor = interceptor;
}

Now, let's imagine a second IIinterceptor implementation that wil calculate a certain reduction to the calculated price:

public class ReductionInterceptor implements IInterceptor {

	public function ReductionInterceptor() {
		super();
	}

	public function intercept(invocation:IMethodInvocation):void {
		if (invocation.kind === InvocationKind.METHOD) {
			//first let the original method calculate the order price:
			var price:Number = invocation.targetMethod.apply(invocation.targetInstance, invocation.arguments);
			//Now let's give a 10% reduction:
			price -= ((price / 100) * 10);
			//Set proceed to false to prevent the original method from being invoked again
			invocation.proceed = false;
			//And set the altered price as the return Value:
			invocation.returnValue = price;
		}
	}
}

Now add the interceptor to the BasicMethodInvocationInterceptor:

function createMethodInterceptor(event:ProxyFactoryEvent):void {
	var interceptor:BasicMethodInvocationInterceptor = new event.methodInvocationInterceptorClass() as BasicMethodInvocationInterceptor;
	interceptor.interceptors[interceptor.interceptors.length] = new TracingInterceptor();
	interceptor.interceptors[interceptor.interceptors.length] = new ReductionInterceptor();
	event.methodInvocationInterceptor = interceptor;
}

Introductions

The last, and potentially most powerful, feature is called 'introductions', an AOP term. People might recognize this as 'Partial Classes' or 'Mixins' as well.

What this feature offers is the ability to merge an existing class into a generated proxy class, adding its behavior to the resulting class.

These introduced classes have a few limitations though:

  • They cannot have any constructor arguments.
  • They can only inherit from the Object class.
ATTENTION: Currently there are still some issues introducing methods, it is therefore adviced *not* too use try/catch blocks in introduced classes. Failing to do so results in verification errors in release builds of the code. The AS3Commons team hopes to have these issues resolved as soon as possible.

Let's take an actual example to illustrate just how this could work in the real world:

Let's take this ordinary boring value object:

public class Order {
	private var _id:int;
	public function get id():int {
		return _id;
	}
	public function set id(value:int):void {
		_id = value;
	}
	
	private var _date:Date;
	public function get date():Date {
		return _date;
	}
	public function set date(value:Date):void {
		_date = value;
	}

	private var _price:Number;
	public function get price():Number {
		return price;
	}
	public function set price(value:Number):void {
		_price = value;
	}
}

Now suppose we'd like to keep track of the changes to this object by adding a isDirty property, which is supposed to return true if a property has been changed.

One problem, we don't have access to the source of the object. This is where a dynamic proxy could help out:

First there is the IChangeTrackable interface:

public interface IChangeTrackable {
	function get isDirty():Boolean;
	function set isDirty(value:Boolean):void;
}

And the most basic implementation of this interface:

public class PartialChangeTracker implements IChangeTrackable {
	private var _isDirty:Boolean;
	public function get isDirty():Boolean {
		return _isDirty;
	}
	public function set isDirty(value:Boolean):void {
		_isDirty = value;
	}
}

That's all that's needed, now the proxy can be defined with an introduction:

var proxyFactory:IProxyFactory = new ProxyFactory();
var classProxyInfo:IClassProxyInfo = proxyFactory.defineProxy(Order, null, _applicationDomain);
classProxyInfo.introduce(PartialChangeTracker);
proxyFactory.generateProxyClasses();
proxyFactory.loadProxyClasses();

And that's it, if afterwards the proxy is instantiated, the instance can actually be cast to IChangeTrackable:

var order:Order = proxyFactory.createProxy(Order) as Order;
var dirty:Boolean = IChangeTrackable(order).isDirty;
//dirty == false

To update the isDirty property an IInterceptor implementation is needed, this could look like this:

public class DirtyUpdateInterceptor implements IInterceptor {
	
	public function DirtyUpdateInterceptor() {
		super();
	}
	
	public function intercept(invocation:IMethodInvocation):void {
		if (invocation.kind === MethodInvocationKind.SETTER) {
			if (invocation.arguments[0] != invocation.instance[invocation.targetMember]) {
				invocation.instance.isDirty = true;
			}
		}
	}
}

And that's it, adding this IInterceptor to the IMethodInvocationInterceptor that's been injected into the proxy will make the Order instance's changes trackable.

Another introduction example

Here's an example that illustrates how to augment an IEventDispatcher implementation with an interface that offers several enhancement methods.

Let's define the interface first:

public interface IEventDispatcherEx {
	function removeAll():void;
	function removeListeners(eventType:String):void;
	function getCountListeners(eventType:String=null):uint;
	function getListeners(eventType:String=null):Array;
}

The implementation can look like this:

public class EventDispatcherExImpl implements IEventDispatcherEx {
	
	as3commons_bytecode var listenersLookup:Dictionary = new Dictionary();
	
	public function EventDispatcherExImpl() {
		super();
	}
	
	public function removeAll():void {
		for each(var type:String in listenersLookup) {
			var listeners:Array = this.as3commons_bytecode::listenersLookup[type] as Array;
			for each(var func:Function in listeners) {
				this['removeEventListener'](type, func);
			}
		}
	}
	
	public function removeListeners(eventType:String):void {
		var listeners:Array = this.as3commons_bytecode::listenersLookup[eventType] as Array;
		if (listeners != null) {
			for each(var func:Function in listeners) {
				this['removeEventListener'](eventType, func);
			}
		}
	}
	
	public function getCountListeners(eventType:String=null):uint {
		var result:uint = 0;
		if (eventType == null){
			for each(var type:String in listenersLookup) {
				var listeners:Array = this.as3commons_bytecode::listenersLookup[type] as Array;
				result += listeners.length;
			}
		} else {
			var listeners:Array = this.as3commons_bytecode::listenersLookup[eventType] as Array;
			if (listeners != null) {
				result += listeners.length;
			}
		}
		return result;
	}
	
	public function getListeners(eventType:String=null):Array {
		return this.as3commons_bytecode::listenersLookup[type] as Array;
	}
}

Note that the listenersLookup member is scoped to the as3commons_bytecode namespace. This is on purpose because this class is meant to be merged into another class, scoping its members to a namespace reduces the risks of duplicate members in the generated class.

Now the class is ready to be introduced (merged) into a proxy class, let's suppose there is an IEventDispatcher implementation called MyEventDispatcher:

var proxyfactory:IProxyFactory = new ProxyFactory();
var classProxyInfo:IClassProxyInfo = proxyFactory.defineProxy(MyEventDispatcher, null, _applicationDomain);
classProxyInfo.introduce(EventDispatcherExImpl);
classProxyInfo.proxyMethod("addEventListener");
classProxyInfo.proxyMethod("removeEventListener");
proxyFactory.generateProxyClasses();
proxyFactory.loadProxyClasses();

Of course the mechanism to tie the introduced clas together with the proxy is done using an IInterceptor:

public class EventDispatcherExInterceptor implements IInterceptor {
	
	public function EventDispatcherExInterceptor() {
		super();
	}
	
	public function intercept(invocation:IMethodInvocation):void {
		if (invocation.kind === InvocationKind.METHOD) {
			switch (invocation.targetMember.localName) {
				case 'addEventListener':
					interceptAddEventListener(invocation);
					break;
				case 'removeEventListener':
					interceptRemoveEventListener(invocation);
					break;
				default:
					break;
			}
		}
	}
	
	public function interceptAddEventListener(invocation:IMethodInvocation):void {
		var eventType:String = String(invocation.arguments[0]);
		if (invocation.targetInstance.as3commons_bytecode::listenersLookup[eventType] == null) {
			invocation.targetInstance.as3commons_bytecode::listenersLookup[eventType] = [];
		}
		var arr:Array = invocation.targetInstance.as3commons_bytecode::listenersLookup[eventType];
		arr[arr.length] = invocation.arguments[1];
	}

	public function interceptRemoveEventListener(invocation:IMethodInvocation):void {
		var eventType:String = String(invocation.arguments[0]);
		if (invocation.targetInstance.as3commons_bytecode::listenersLookup[eventType] != null) {
			var arr:Array = invocation.targetInstance.as3commons_bytecode::listenersLookup[eventType];
			var idx:int = arr.indexOf(eventType);
			arr.splice(idx, 1);
		}
		arr[arr.length] = invocation.arguments[1];
	}

}

This is not a perfect implementation of such a mechanism, since the EventDispatcherExImpl doesn't take into account weak referenced event listeners or if the capture phase is used or not, but this example is not meant to showcase a perfect implementation, merely a pattern.

All of this could, of course, be solved in most cases by having the necessary classes inherit from a base class, but this is not always possible to achieve, in these cases a dynamic proxy might offer a better solution.

Dynamically implementing interfaces

A second, and perhaps more convenient, way to add interfaces to a proxy is by dynamically implementing them and letting the susual interceptor mechanism handle its implementation.

Getting this to work is fairly easy, use the implementedInterface() method on the IClassProxyInfo and pass into it an interface class:

var classProxyInfo:IClassProxyInfo = proxyFactory.defineProxy(MyClass, null, _applicationDomain);
classProxyInfo.implementInterface(IEventDispatcherEx);

The ProxyFactory afterwards will make sure that all the members of the specified interface are dynamically added to the proxy class.

Finally, the usual interception mechanism can be applied to provide the actual implementation of the interface methods.

Proxying aliased classes

There might be scenario's one can think of where proxying a value object returned from a webserver can add an extra benefit.

In this section it is explained how this can be achieved.

First, let's imagine the value objects, probably looking something like this:

[RemoteClass("com.myclasses.vo.MyValueObject")]
public class MyValueObject {
	private var _name:String;
	private var _width:Number;
	private var _height:Number;

	public function get name():String {
		return _name;
	}
	public function set name(value:String):void {
		_name = value;
	}

	public function get width():Number {
		return _width;
	}
	public function set width(value:Number):void; {
		_width = value;
	}

	public function get height():Number {
		return _height;
	}
	public function set height(value:Number):void {
		_height = value;
	}
}

Now suppose every value object would need an instantiation timestamp, as defined in this following interface and implemented in the specified class:

public interface ITimeStampable {
	function get timestamp():Date;
}

public class PartialTimeStampable implements ITimeStampable {
	private var _timestamp:Date = new Date();
	
	[Transient]
	public function get timestamp():Date {
		return _timestamp;
	}
}

All that remains is figuring out which classes ought to be proxied and their class aliases overriden:

var classNames:Array = ByteCodeType.fromLoader(Application.loaderInfo);
var _applicationDomain:ApplicationDomain = Application.loaderInfo.applicationDomain;
var classNames:Array = ByteCodeType.getClassesWithMetadata('RemoteClass');
var proxyFactory:IProxyfactory = new ProxyFactory();
for each(var className:String in classNames) {
	var classProxyInfo:IClassProxyInfo = proxyFactory.defineProxy(_applicationDomain.getDefinition(className) as Class, null, _applicationDomain);
	classProxyInfo.proxyMethodScopes = ProxyScope.NONE;
	classProxyInfo.proxyAccessorScopes = ProxyScope.NONE;
	classProxyInfo.introduce(PartialTimeStampable);
}
proxyFactory.addEventListener(Event.COMPLETE, proxiesLoadedHandler);
proxyFactory.generateProxyClasses();
proxyFactory.loadProxyClasses();

function proxiesLoadedHandler(event:Complete):void {
	var classNames:Array = ByteCodeType.getClassesWithMetadata('RemoteClass');
	for each(var className:String in classNames) {
		var clazz:Class = _applicationDomain.getDefinition(className) as Class;
		var proxyInfo:ProxyInfo = proxyFactory.getProxyInfoForClass(clazz);
		var type:Type = Type.forClass(clazz);
		var classAlias:String = Metadata(type.getMetadata('RemoteClass')[0]).getArgument('alias').value;
		registerClassAlias(classAlias, proxyInfo.proxyClass);
	}
}

And that's it, any objects coming from the remote server that are associated with the specified alias will be deserialized to the proxy value objects containing the new timestamp property that initializes to the current date.

What is the purpose of all this?

The proxy API in as3commons-bytecode isn't meant as a complete end solution for all proxying needs. Instead it only offers the basic building blocks on top of which a more elaborate proxying system can be built. Its target audience includes framework developers in that respect.

The AS3Commons team encourages developers to write their own IMethodInvocationInterceptor implementations and perhaps hook the proxying system into an IoC container or any other type of application framework.