Archive for the 'flex' Category

making mx.rpc.xml.XMLDecoder play nice with xsi:type

Sunday, August 23rd, 2009

In previous posts I have outlined how to use the inbuilt (and well hidden) XML Schema classes that are available in the mx.rpc.xml package in Flex.  Utilising SchemaManager and SchemaTypeRegistry one can quickly register specific ActionScript classes with specific types defined within an xml schema (XSD). Once set up it is simply a matter of using XMLDecoder and XMLEncoder to automatically serialise between XML and ActionScript and voila! the work is done.

That is unless you happen to have elements with your xml file that use an xsi:type attribute to indicate that their contents is actually that of a derivative element (such as an extension, restriction, etc). In these cases Flex just ignores the xsi:type and decodes against the original element type – which aint much help. What’s suprisising is that the Flex classes have been built with xsi:type in mind (storing the type in custom classes implementing IXMLSchemaInstance), but just seems to have been missed when implementing XMLDecoder – always saves the element type in the xsitype property of IXMLSchemaInstance

Whether you love it, hate it or are just indifferent,  xsi:type is part of the XSD standard and all it takes is a few tweaks for Flex to handle it correctly.

I’ve included a CustomXMLDecoder class below, but firstly:

A quick primer on xsi:type

If you are unfamiliar with xsi:type here is  a quick example of it in action:

In an XSD file we have a complex type called user:

<xs:complexType name="User">
 <xs:sequence>
 <xs:element name="username" type="xs:string" />
 <xs:element name="password" type="xs:string" />
 </xs:sequence>
 </xs:complexType> 

And we have another complex type that is an extension of User called InternalUser :

<xs:complexType name="InternalUser">
 <xs:complexContent>
 <xs:extension base="User" >
 <xs:sequence>
 <xs:element name="staffId" type="xs:string" />
 </xs:sequence>
 </xs:extension>
 </xs:complexContent>
 </xs:complexType>

In an XML file implementing this schema we have a set of User elements. As you can see below one of which includes contains an xsi:type attribute that indicates that the contents is actually that of an InternalUser.

<user >
 <username>joeCitizen</username>
 <password>1234</password>
 </user>
 <user xsi:type="InternalUser" >
 <username>jamesBond</username>
 <password>5678</password>
 <staffId>007</staffId>
 </user>

CustomXMLDecoder

After hours of trawling through  mx.rpc.xml.XMLDecoder, it was surprisingly straight forward to fix the shortcoming by overriding a couple of methods within XMLDecoder.

As an added tweak i’ve included a property to the class that determines the behaviour when attemptying to decode an xsi:type that hasn’t been registered with the SchemaTypeRegistry.

ignoreXSITypeIfNotRegistered:Boolean = false;

If this property is set to true then the decoder will ignore an xsi:type that is not registered against an ActionScript class, and try to decode it against the original element type instead (esentially replicating the functionality of XMLDecoder). This ensures that unexpected xsi:type extensions to a element  are decoded as the element type rather than generic object proxies.

If the xsi:type is registered then it will always use it.

Here is the class:

package
{
import mx.rpc.xml.*;
public class CustomXMLDecoder extends XMLDecoder
 {

 public function CustomXMLDecoder()
 {
 super();
 }

 /**
 * Set this flag if you want unregistered xsi types to be ignored (and objects to be decoded against the
 * base element type instread).
 * If the xsi type is registered then it will always be used over the base element type
 */
 public var ignoreXSITypeIfNotRegistered:Boolean = false;

 /**
 * Decodes a element based on the xsi:type. If the type isn't registered then it
 * checks the ignoreXSITypeIfNotRegistered property of the class.
 *
 * If true - decodes against the element type (and ignores the xsi:type)
 * If false - uses object proxy.
 */
 public override function decodeElementTopLevel(definition:XML, elementQName:QName, value:*):*
 {
 var content:*;

 if(value is XML)
 {
 var xsiType:QName = getXSIType(value);
 var isXSITypeRegistered:Boolean = typeRegistry.getClass(xsiType) != null

 if(xsiType != null && (isXSITypeRegistered || ignoreXSITypeIfNotRegistered == false))
 {
 content = createContent(xsiType);
 decodeType(xsiType, content, elementQName, value);
 return content;
 }
 }
 return super.decodeElementTopLevel(definition, elementQName, value);
 }

 /**
 * Decodes agains the xsi:type (if available) rather than the defined element type
 */
 public override function decode(xml:*, name:QName=null, type:QName=null, definition:XML=null):*
 {
 if(xml is XML)
 {
 var xsiType:QName = getXSIType(xml);

 if(xsiType != null)
 type = xsiType;
 }
 return super.decode(xml, name, type, definition);
 }
}

Hope that helps other people out there  – as this was previously the only real show stopper for using the Schema classes in some of our projects.

———

One last thing,

Can anyone point out to how override the decoding of nested arrays of elements?

Ususally XML will be structured so that an array of items is wrapped within a parent element

e.g the child ‘item’ elements are located within an <items/> element

<item>
 <name>Parent</name>
 <items>
   <item >
     <name>Child A</name>
   </item>
   <item >
     <name>Child B</name>
   </item>
 </items>
</item>

In Flex this data may be registered to a  class such as this one:

package
{
 [Bindable]
 public class ItemVO
{
 public var name:String;
 public var items:ArrayCollection;

 public function ItemVO():void
 {
 }
}
}

Unfortunately the decoder always includes the extra level when decoding – resulting in an ArrayCollection containing a single item (an ArrayCollection) that contains the array of items.

Does anyone know of a way to map this relationship better so that the items.item in the xml maps directly to the items ArrayCollection in the Class?

Ta,

Dom

Adobe reopens discussion around the Flex 4 namespaces and the ‘Fx’ prefix on components

Tuesday, February 10th, 2009

[UPDATE] A decision has been made and the Fx prefix is no more – http://www.adobeforums.com/webx/.59b7e849

——-

I don’t like reposting Flex related news; however I’m please to see that Adobe have decided to revisit their original naming strategy for the new Flex 4 components.

There is a good discussion happening on their forums on Flex 3/4 component compatibility – the distinction between flex 3 and flex 4 components, namespace/naming conventions, and IDE/documentation/CSS implications.

It is a response to the community’s criticism of the whole “Fx” thing – naming the new Flex 4 components with a class prefix to distinguish them – such as “FxButton, “FxList”, etc.

Most developers seem to agree that separate namespaces for the halo and spark (gumbo) components would be most consistent and future proof and doesn’t further complicate usage considering that most developers already utilise additional namespaces for custom components and 3rd party libraries.

The general consensus seems to support three namespaces – the default for language specific elements – e.g. <Style>, <Script>), and two separate namespaces for the Flex 3 and Flex 4 components ( e.g. – <mx:Button> and <fx:Button>)

I have to agree that this solution is preferable over the original “Fx” class name prefix strategy. A key concern/priority for Adobe seems to be minimizing the complexity of the initial learning curve for new Flex developers (part of their reasoning behind choosing class prefixes over additional namespaces).

I agree with this concern, but believe that due to the overlapping functionality within the two component sets, any proposed solution is going to increase this complexity but at least the latter provides a consistent usage of xml namespace that existing flex developers will understand immediately, and new developers will appreciate in time.
Adobe is due to finalise their decision soon, and the discussion is ongoing.

Forum discussion here:
http://www.adobeforums.com/webx?128@@.59b7cdf0

Original Post here:
http://davidzuckerman.com/adobe/2009/02/10/help-us-decide-where-to-go-with-flex-4/

Flex 3, XML Schemas & automatic mapping of AS classes to XSD element definitions (Part 2)

Sunday, November 30th, 2008

This is a set of posts documenting my experiences with utilising functionality within the Flex SDK that provides the automatic mapping of custom ActionScript classes to element definitions within an XML Schema (XSD).

1.  Part 1 – Introduction and background
2.  Part 2 – Overview of Flex’s XML Schema classes (inc example code)

Part 2 – Overview of Flex’s XML Schema classes (including example code)

This post covers how to take advantage of these classes (including example code) – as at the time of writing there doesn’t seem to be any discussion of these features by Adobe or the community at large. I’ll also list a few caveats we have come across in using these classes.

Read the rest of this entry »

Flex 3, XML Schemas & automatic mapping of AS classes to XSD element definitions (Part 1)

Sunday, November 30th, 2008

This is a set of posts documenting my experiences with utilising functionality within the Flex SDK that provides the automatic mapping of custom ActionScript classes to element definitions within an XML Schema (XSD).

1.  Part 1 – Introduction and background
2.  Part 2 – Overview of Flex’s XML Schema classes (inc example code)

Part 1 – Introduction and background

This post explains some reasons on why the automated mapping of ActionScript classes to XML Schema definitions can be a better alternative to other data integration options available to Flex (in certain circumstances).

Read the rest of this entry »

Flex: ObjectUtil.copy() throws errors for classes with custom namespace properties.

Tuesday, February 26th, 2008

The easiest way to clone an instance of a class in Flex is to use the inbuilt ObjectUtil.copy() . This function serialises the entire object into an array of bytes and then deserialises it back into a completely new instance of that class. All that needs to be added to a class to ensure that it is correctly deserialised is to include the [RemoteClass] metadata tag above the class definition.

Rather than explaining it all here, I suggest you have a read of Darron Schall’s explanation of it here.

I’ve used this method for cloning custom objects in several projects without issue, but when I implemented this functionality in a current project, everytime I called ObjectUtil.copy() I received the following error:

ArgumentError: Error #2004: One of the parameters is invalid.
    at flash.utils::ByteArray/writeObject()

There is only one parameter for ObjectUtil.copy() – the object to be copied, so obviously there was something in one of my classes that didn’t like being deserialised. Unfortunately by this time there was already a reasonable inheritance chain going in my classes, and eventually I had to start stripping bits out of my classes (and superclasses) until the error went away.

It turns out that the culprit was a custom namespace property in my superclass. Whenever the namespace was defined, ByteArray.writeObject() fails to deserialise the byte array, and the copy fails.

package
{
    [RemoteClass]
    public class Example
    {
        public var ns:Namespace = new Namespace("http://www.misprintt.net");

        public function Example()
        {

        }
    }
}

Cloning an instance of this class will always throw an error:

var example:Example();= new Example();
var o:Object = ObjectUtil.copy(example);

Luckily the solution is also describe in Darron’s post. While he doesn’t indentify what problems he was having, he explains how he used the [Transient] metadata tag to avoid issues with ObjectUtil.copy().

So now that the culprit has been identified, it is just a matter of adding the [Transient] metadata tag to avoid the namespace being serialised in the first place.

package
{
    [RemoteClass]
    public class Example
    {
	[Transient]
        public var ns:Namespace = new Namespace("http://www.misprintt.net");

        public function Example()
        {

        }
    }
}

Anyway, hopefully this saves some time for those trying to decipher yet another one of those vague flash player errors :)

Limitations of Drag And Drop animations in Flex

Sunday, November 11th, 2007

One of the key benefits of using Flex for the end user is a consistent experience when interacting with on screen elements. While the look/skin can vary greatly, the underlying behaviours remain consistent, making the site or application more usable. While Flex provides a default implementation to each step in an interaction, it generally allows customization of the visual state through the various events associated with each component type. Hence we have custom animations and transitions between states to implement the most appropriate behaviour in an individual project.

A good example of this is Flex’s inbuilt Drag and Drop. Generally on the web, drag and drop functionality varies greatly from implementation to implementation. Many cases don’t provide enough visual feedback to the user to fully utilise the benefits of a drag and drop system – easy, direct manipulation of information on screen.

Drag and Drop functionality within Flex is pretty solid. It works out of the box with inbuilt components, and adding it to custom components is relatively straight forward (once you understand the order of all the events in a drag-drop interaction by reading this PDF- http://blogs.adobe.com/flexdoc/pdf/dragdrop.pdf). It also allows for a reasonable amount of customization to the visual states during a drag-drop process, with the exception below.

Flex provides two possible behaviours when an object is dropped:

  1. The drop is rejected and the dragged item animates back to it’s original position
  2. The drop is accepted and the dragged item animates into the new position.

These behaviours are correct, however there is no means to override the actual animations that occur as a result of these behaviours, so we are stuck with the following “zoom to mouse position” transition when a drop is accepted (from mx.managers.dragClasses.DragProxy) :

 

 

// Zoom into mouse location to show drag was accepted.
var e:Zoom = new Zoom(this);
e.zoomWidthFrom = e.zoomHeightFrom = 1.0;

e.zoomWidthTo = e.zoomHeightTo = 0;

e.duration = 200;

e.play();

var m:Move = new Move(this);
m.addEventListener(EffectEvent.EFFECT_END, effectEndHandler);

m.xFrom = x;

m.yFrom =
this.y;
m.xTo = parent.mouseX;

m.yTo = parent.mouseY;

m.duration = 200;

m.play();

This transition may work well when dragging data from one list to another (which is the most common use case when using the inbuilt components), but can look a bit much when dragging a large container around the screen.

You drag an object from one area of the screen to another, and when you release the mouse it scales down into obscurity before appearing in its new position. There should be a means to override this default effect.

In this example try dropping the item in the bottom right corner of one of the (white) drop areas. This transition looks wrong as the mouse coordinates are not always the intended final destination of the dropped object.

Basically there should be some way to define or override the animation that occurs on a successful drop event. It seems surprising that this animation is hardcoded within the framework, while every other visual state during the drag/drop operation is customisable.

I know it is hardly a show stopper, but I’ve submitted an enhancement request to the Flex Bug and Issue Management System (https://bugs.adobe.com/jira/browse/SDK-13472) as it is an UI issue that has already arisen in one of our commercial projects.

– D