Archive for August, 2009
ActionScript Dependency Injection With RemoteClass Metadata Issue With Fix - UPDATED
Posted by brianr in actionscript, blazeds, cairngorm, spring on August 31st, 2009
NOTE: My fix might be a little overkill, so I offer a simpler approach at the bottom of this post…and since this post still contains some good info on dynamically mapping classes at runtime leveraging the registerClassAlias() method, I decided to leave it as is sans this simple note.
Say you’re using Spring ActionScript (SAS) or Swiz or some other ActionScript framework for Dependency Injection (DI) in conjunction with the RemoteObject…in most cases you’d like to map custom ActionScript Request and Response objects to a corresponding server-side Request and Response object and you typically do so with a small bit of metadata in your AS class — just for an example, let’s say we have a Java LoginService with the following method signature:
public LoginResponseDTO login(LoginRequestDTO request) throws LoginException
And the Java LoginRequestDTO looks like:
package com.domain.myproj.dto.request;
public class LoginRequestDTO
{
public String username;
public String password;
}
Then we’d most likely have a corresponding LoginRequestDTO in ActionScript with the following class definition:
package test
{
[RemoteClass(alias="com.domain.myproj.dto.request.LoginRequestDTO")]
public class LoginRequestDTO extends test.AbstractRequestDTO
{
public var username:String;
public var password:String;
}
}
And via the magic of the client-side Flash Player and the server-side AMF Remoting Gateway in BlazeDS / LCDS / WebORB / GraniteDS, our ActionScript Request and Response Objects are serialized and deserialzied into their Java counterparts and all is well…the thing is, this is really only done with some big help from the Flex compiler and the all important RemoteClass metadata…ok, so what?…let’s do some further questioning and hypothesizing…
Well, let’s say you’re injecting your Business Delegates or whatever objects you’re using to actually invoke the server-side LoginService, where you’re also leveraging your cool, custom AS Req/Resp objects…well if you’re injecting your BDs, then you’re kind of injecting these other objects too, which means the compiler never actually sees the RemoteClass metadata in your Req/Resp objects…now this is very important, so I’ll repeat it in a slightly different way and with more definition to it’s importantce:
If the compiler doesn’t actually know about or see the RemoteClass metadata, then not only will the mapping of your custom AS Req/Resp objects that are supposed to map to custom Java Req/Resp objects not happen, but even worse is that core AS Remoting objects that map to their corresponding core Java Remoting Objects (part of the very framework that makes the RemoteObject possible) does not take place.
Go ahead…create an example and you’ll get a runtime error probably saying something like:
TypeError: Error #1034: Type Coercion failed: cannot convert Object@13e9921 to mx.messaging.messages.ErrorMessage.
So now you have 2 issues with the latter being the first priority, b/c if you don’t fix that then you don’t have to even worry about the custom mappings…head in hands…what to do? Well, I know Flash guys or doods writing in pure AS3 without the Flex Framework also run into issues when trying to leverage the RemoteObject, so I googled around a bit and found the answer with the registerClassAlias() method.
What we need to do is map each of the core AS Objects to the core Java Objects that are required for Java-RPC — http://forums.adobe.com/thread/295996
The registerClassAlias method allows developers to map client-side AS objects to server-side objects at runtime so the Flash Player can create the correct mappings…so to fix our issues we need to register the core objects and our custom objects.
I decided to wrap this in 2 objects: 1 for the framework mappings and a 2nd for the custom mappings:
RegisterDataServicesClassAliases
/**
* Web App Solution Confidential Information
* Copyright 2009, Web App Solution
*
* @author Brian Riley
* @date July, 6, 2009
*/
package com.webappsolution.roserviceinspector.util
{
import com.webappsolution.springactionscript.util.IRegisterRemoteObjectClassAliases;
import com.webappsolution.springactionscript.util.RegisterRemoteObjectClassAliases;
public class RegisterDataServicesClassAliases extends RegisterRemoteObjectClassAliases implements IRegisterRemoteObjectClassAliases
{
/**
* Register all the custom request and response objects for the application.
*/
override public function registerCustomFlexDataServicesImpl():void
{
// REQUESTS
//
registerClassAlias("com.domain.myproj.dto.request.LoginRequestDTO", com.domain.myproj.dto.request.LoginRequestDTO);
// RESPONSES
//
}
}
}
RegisterRemoteObjectClassAliases
/**
* Web App Solution Confidential Information
* Copyright 2009, Web App Solution
*
* @author Brian Riley
* @date July, 29, 2009
*/
package com.webappsolution.springactionscript.util
{
import flash.net.registerClassAlias;
import mx.collections.ArrayCollection;
import mx.messaging.config.ConfigMap;
import mx.messaging.messages.*;
import mx.utils.ObjectProxy;
/**
* This little gem maps client-side ActionScript objects to their servber-side Java counterparts
* at runtime.
*
* <p>
* Normally this is done via the metatdata tag for RemoteObjects [RemoteClass(alias="com.domain.project.MyDTO")]
* and the compiler automatically creates the base AS to Java class mappings for the Flex Data Services in
* LCDS / BlazeDS / WebORB / GraniteDS...
* </p>
*
* <p>
* However, there are cases where developers either don't create the metadata or inject these DTOs
* at runtime and thus the compiler never actually sees the metadata, so we're left to do the class
* mappings at runtime.
* </p>
*
* <p>
* This class provides developers with a couple options: The developer can choose to map all the Flex
* Data Service components with the <code>public static registerFlexDataServices()</code> method or
* they can simply call the <code>public static registerAll()</code> method; they can also put a list
* of custom mappings for custom requerst and response objects in the
* <code>public static registerCustomFlexDataServices()</code> method.
* </p>
*/
public class RegisterRemoteObjectClassAliases
{
/**
* Constructor
*/
public function RegisterRemoteObjectClassAliases()
{
}
/**
*
*/
public function registerAll():void
{
registerFlexDataServices();
registerFlexDataServicesMisc();
registerCustomFlexDataServices();
}
/**
* Registers the base Flex Data Service Java reguest and response objects to the base
* ActionScript reguest and response objects.
*/
public function registerFlexDataServices():void
{
/*
http://forums.adobe.com/thread/295996
I think one problem is that the various mx.messaging.messages.Message
implementations have not called registerClassAlias() for each
of their types. In Flex, the compiler notices the [RemoteClass] metadata
on each ActionScript class and codegens static initializer code to call
registerClassAlias() while the application is initializing (so
that it occurs before any data is sent or received).
Note you can see this generated code if you specify
-keep-generated-actionscript=true on the command line arguments for
mxmlc. For compiling a file called test.mxml, find the
/generated/_test_FlexInit-generated.as file and notice the calls to
registerClassAlias.
*/
// See http://www.mail-archive.com/flexcoders@yahoogroups.com/msg74512.html
// For explanation as to why this is needed. Without it, messages were not getting mapped correctly
// from server.
registerClassAlias("flex.messaging.messages.RemotingMessage", RemotingMessage);
registerClassAlias("flex.messaging.messages.ErrorMessage", ErrorMessage);
registerClassAlias("flex.messaging.messages.CommandMessage",CommandMessage);
registerClassAlias("flex.messaging.messages.AcknowledgeMessage", AcknowledgeMessage);
// registerClassAlias("flex.messaging.io.ArrayList", ArrayList);
registerClassAlias("flex.messaging.config.ConfigMap", ConfigMap);
registerClassAlias("flex.messaging.io.ArrayCollection", ArrayCollection);
registerClassAlias("flex.messaging.io.ObjectProxy", ObjectProxy);
// You may want to register pub/sub and other rpc message types too...
registerClassAlias("flex.messaging.messages.HTTPMessage", HTTPRequestMessage);
registerClassAlias("flex.messaging.messages.SOAPMessage", SOAPMessage);
registerClassAlias("flex.messaging.messages.AsyncMessage", AsyncMessage);
registerClassAlias("flex.messaging.messages.MessagePerformance Info", MessagePerformanceInfo);
}
/**
* Additional message types...doesn't work in Flex 2.0.1 SDK, so comment out the
* the body of the method if that's the case.
*/
public function registerFlexDataServicesMisc():void
{
// registerClassAlias("DSA", AsyncMessageExt); // doesn't work in Flex 2.0.1 SDK
// registerClassAlias("DSC", CommandMessageExt); // doesn't work in Flex 2.0.1 SDK
// registerClassAlias("DSK", AcknowledgeMessageExt); // doesn't work in Flex 2.0.1 SDK
}
/**
* Registers the custom Java reguest and response objects to the custom ActionScript reguest and response objects.
* Developers should list their custom objects here.
*/
public function registerCustomFlexDataServices():void
{
// map the Java Data Transfer Object passed over HTTP back to Flex to the AS object
registerCustomFlexDataServicesImpl();
}
/**
* Concrete classes must override this method, as this is just a hook operation.
*/
public function registerCustomFlexDataServicesImpl():void
{
// concrete classes must override this bad boy
}
}
}
And then I simply call the following somewhere in my app’s initialization process (very early on):
private function registerDataServices():void
{
logger.debug("registerDataServices");
var registerROAliases:RegisterDataServicesClassAliases;
// since we're injecting classes at runtime we need to set up the registerClassAlias() to
// Flex Data Service classes manually
registerROAliases = new RegisterDataServicesClassAliases();
registerROAliases.registerAll();
}
And voila! We’re back in business.
I’d like to thank my local, Boston Adobe Flex guru for providing the basic solution to my issue in the following link: http://forums.adobe.com/thread/295996
UPDATED FIX:
So I’m an idiot or rather someone that tends to overarchitect/think things sometimes…everywhere else in my app I simply make sure my classes injected at runtime are compiled into the app by simply referencing them somewhere else in the app or by putting them into a properties file like so:
LoginRequestDTO = ClassReference("com.domain.myproj.dto.request.LoginRequestDTO")
This will force the compilation of the LoginRequestDTO and thus allow the compiler to see the RemoteClass metadata…but at least you know more about what the metadata does and how it works in conjunction with the Flex compiler
dependency-injection, java-rpc, register-class-alias, remote-object, remoteclass-metadata
Centering the Label Vertically in a FormItem
So you’re coding up some form items and the glorious designer is showing the label for the form item centered vertically, or, at the bottom.

![]()
Piece of cake says I and I start to look for the props to do so. Lo and behold, they don’t exist. WTF??
Google this and google that and no luck!!
Great, now what do I do?
Well, it’s kinda hacky, but it works.
I call this function on the creationComplete event of the FormItem:
private function centerLabel(evt:FlexEvent):void
{
var fi:FormItem = FormItem(evt.currentTarget) as FormItem;
var lbl:Label = fi.itemLabel as Label;
lbl.move( lbl.x, lbl.y + (lbl.height/2) );
}
Enjoy
-
-
You are currently browsing the archives for August, 2009
-
Archives
- April 2011 (2)
- March 2011 (1)
- February 2011 (1)
- January 2011 (1)
- December 2010 (5)
- October 2010 (4)
- September 2010 (1)
- August 2010 (2)
- April 2010 (6)
- March 2010 (2)
- January 2010 (2)
- December 2009 (1)
- November 2009 (7)
- October 2009 (3)
- September 2009 (1)
- August 2009 (3)
- July 2009 (6)
- June 2009 (5)
- May 2009 (9)
- April 2009 (8)
- March 2009 (2)
- January 2007 (1)
- August 2006 (1)
-
Meta