diff --git a/FlexXB.iml b/FlexXB.iml new file mode 100644 index 0000000..636ac06 --- /dev/null +++ b/FlexXB.iml @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/README.md b/README.md index 25b2601..ad68221 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,10 @@ FlexXB ====== FlexXB fork, optimized for mobile applications + +See https://code.google.com/p/flexxb/ + +Optimized XML serializer/deserializer, few times faster than original version: +* faster [reflection] (https://github.com/kemsky/RObject) +* using variables instead of accessor functions +* other minor optimizations (cache etc.) \ No newline at end of file diff --git a/bin/empty.dir b/bin/empty.dir new file mode 100644 index 0000000..e69de29 diff --git a/docs/FlexXB.doc b/docs/FlexXB.doc new file mode 100644 index 0000000..87fd483 Binary files /dev/null and b/docs/FlexXB.doc differ diff --git a/libs/RObject.swc b/libs/RObject.swc new file mode 100644 index 0000000..3bf8b7a Binary files /dev/null and b/libs/RObject.swc differ diff --git a/src/com/googlecode/flexxb/VERSION.as b/src/com/googlecode/flexxb/VERSION.as new file mode 100644 index 0000000..d6249f4 --- /dev/null +++ b/src/com/googlecode/flexxb/VERSION.as @@ -0,0 +1,63 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb +{ + + /** + * + * @author Alexutz + * + */ + public final class VERSION + { + /** + * + * @return + * + */ + public static function get Version():String + { + return "2.3.0"; + } + + /** + * + * @return + * + */ + public static function get Name():String + { + return "FlexXB"; + } + + /** + * + * @return + * + */ + public static function get Link():String + { + return "http://code.google.com/p/flexxb"; + } + + public function VERSION() + { + throw new Error("Do not instanciate this class"); + } + + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/AccessorType.as b/src/com/googlecode/flexxb/annotation/contract/AccessorType.as new file mode 100644 index 0000000..0428500 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/AccessorType.as @@ -0,0 +1,128 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + + /** + * Enumeration defining field acces types. A class field can be accessed + * in readonly, writeonly or readwrite modes. + * @author Alexutz + * + */ + public class AccessorType + { + /** + * read only + */ + public static const READ_ONLY:AccessorType = new AccessorType("readonly"); + /** + * write only + */ + public static const WRITE_ONLY:AccessorType = new AccessorType("writeonly"); + /** + * read write + */ + public static const READ_WRITE:AccessorType = new AccessorType("readwrite"); + + /** + * Obtain an AccessorType instance from a string value. If the value is + * invalid the READ_WRITE instance will be returned by default. + * @param value + * @return + * + */ + public static function fromString(value:String):AccessorType + { + switch (value) + { + case "readonly": + return READ_ONLY; + break; + case "writeonly": + return WRITE_ONLY; + break; + case "readwrite": + return READ_WRITE; + break; + default: + return READ_WRITE; + } + } + + private static var initialized:Boolean = false; + + { + initialized = true; + } + + private var name:String; + + /** + * Constructor + * @param name + * @private + */ + public function AccessorType(name:String) + { + if (initialized) + { + throw new Error("Use static fields instead."); + } + this.name = name; + } + + /** + * Check if the type is read only + * @return true id type is read only, false otherwise + * + */ + public function isReadOnly():Boolean + { + return READ_ONLY == this; + } + + /** + * Check if the type is write only + * @return true id type is write only, false otherwise + * + */ + public function isWriteOnly():Boolean + { + return WRITE_ONLY == this; + } + + /** + * Check if the type is read-write + * @return true id type is read-write, false otherwise + * + */ + public function isReadWrite():Boolean + { + return READ_WRITE == this; + } + + /** + * Get a string representation of the current instance + * @return + * + */ + public function toString():String + { + return name; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/Annotation.as b/src/com/googlecode/flexxb/annotation/contract/Annotation.as new file mode 100644 index 0000000..8541d44 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/Annotation.as @@ -0,0 +1,153 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + + /** + * This is the base class for a field xml annotation. + *

It obtains basic informations about the field: + *

+ *

+ * @author aCiobanu + * + */ + public class Annotation extends BaseAnnotation + { + public var name:QName; + public var type:Class; + + public var alias:String = ""; + public var useOwnerAlias:Boolean; + public var isPath:Boolean; + public var hasNamespaceDeclaration:Boolean; + + public var xmlName:QName; + + public var nameSpace:Namespace; + + public var namespaceRef:String; + + [ArrayElementType("QName")] + public var qualifiedPathElements:Array; + + /** + * Constructor + * @param descriptor + * + */ + public function Annotation(descriptor:MetaDescriptor = null) + { + super(descriptor); + } + + /** + * Set the annotation namepsace + * + */ + public function setNameSpace(value:Namespace):void + { + nameSpace = value; + if (isPath) + { + var path:QName; + for (var i:int = 0; i < qualifiedPathElements.length; i++) + { + path = qualifiedPathElements[i] as QName; + qualifiedPathElements[i] = new QName(value, path.localName); + } + } + isPath = qualifiedPathElements && qualifiedPathElements.length > 0; + + hasNamespaceDeclaration = nameSpace && nameSpace.uri && nameSpace.uri.length > 0; + + if (namespaceRef == "") + { + nameSpace = null; + } + + xmlName = new QName(nameSpace, alias == "" ? name : alias); + } + + /** + * @private + * @param value name to be set + * + */ + protected function setAlias(value:String):void + { + if (value && value.indexOf(XmlConstants.ALIAS_PATH_SEPARATOR) > 0) + { + var elems:Array = value.split(XmlConstants.ALIAS_PATH_SEPARATOR); + qualifiedPathElements = []; + var localName:String; + for (var i:int = 0; i < elems.length; i++) + { + localName = elems[i] as String; + if (localName && localName.length > 0) + { + if (i == elems.length - 1) + { + internalSetAlias(localName); + break; + } + qualifiedPathElements.push(new QName(nameSpace, localName)); + } + } + } + else + { + internalSetAlias(value); + } + + isPath = qualifiedPathElements && qualifiedPathElements.length > 0; + + xmlName = new QName(nameSpace, alias == "" ? name : alias); + } + + private function internalSetAlias(value:String):void + { + alias = value; + if (!alias || alias.length == 0) + { + alias = name.localName; + } + useOwnerAlias = alias == XmlConstants.ALIAS_ANY; + } + + protected override function parse(descriptor:MetaDescriptor):void + { + super.parse(descriptor); + name = descriptor.fieldName; + type = descriptor.fieldType; + setAlias(descriptor.attributes[XmlConstants.ALIAS]); + + namespaceRef = descriptor.attributes[XmlConstants.NAMESPACE]; + if (namespaceRef == "") + { + nameSpace = null; + } + + hasNamespaceDeclaration = nameSpace && nameSpace.uri && nameSpace.uri.length > 0; + + xmlName = new QName(nameSpace, alias == "" ? name : alias); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/AnnotationFactory.as b/src/com/googlecode/flexxb/annotation/contract/AnnotationFactory.as new file mode 100644 index 0000000..462d12b --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/AnnotationFactory.as @@ -0,0 +1,232 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import avmplus.R; + + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + import com.googlecode.flexxb.core.XmlDescriptionContext; + import com.googlecode.flexxb.serializer.BaseSerializer; + import flash.utils.Dictionary; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * @private + * This Factory will return an annotation instance based on the type required. Since each + * annotation has a specific serializer, it will also provide the serializer instance to be + * used when processing a field. Since they are stateless, serializers do not need to be + * instanciated more than once. + * + * @author Alexutz + * + */ + public final class AnnotationFactory + { + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.annotation.contract.AnnotationFactory"); + + private static const TRUE:Object = {}; + + private var annotationMap:Dictionary = new Dictionary(); + private var annotationIsClass:Dictionary = new Dictionary(); + private var annotationIsMember:Dictionary = new Dictionary(); + private var annotationIsGlobal:Dictionary = new Dictionary(); + private var annotationSerializer:Dictionary = new Dictionary(); + private var annotationClass:Dictionary = new Dictionary(); + private var annotationContext:Dictionary = new Dictionary(); + + /** + * Constructor + * + */ + public function AnnotationFactory() + { + } + + /** + * Check if there is an annotation with the given name registered in the factory. + * @param metaName annotation name + * @return true if an annotation with this name is registered, false otherwise + * + */ + public function isRegistered(metaName:String):Boolean + { + return annotationMap[metaName] != null; + } + + /** + * + * @param metaName + * @return + * + */ + public function isClassAnnotation(metaName:String):Boolean + { + return annotationIsClass[metaName] != null; + } + + /** + * + * @param metaName + * @return + * + */ + public function isMemberAnnotation(metaName:String):Boolean + { + return annotationIsMember[metaName] != null; + } + + /** + * + * @param metaName + * @return + * + */ + public function isGlobalAnnotation(metaName:String):Boolean + { + return annotationIsGlobal[metaName] != null; + } + + /** + * Register a new annotation and its serializer. If it finds a registration with the + * same name and overrideExisting is set to false, it will disregard the current attempt and keep the old value. + * @param name the name of the annotation to be registered + * @param annotationClazz annotation class type + * @param serializerClass instance of the serializer that will handle this annotation + * @param context + * @param overrideExisting + * + */ + public function registerAnnotation(name:String, annotationClazz:Class, serializerClass:Class, context:XmlDescriptionContext, overrideExisting:Boolean = false):void + { + if (overrideExisting || !annotationMap[name]) + { + var json:Object = R.describe(annotationClazz, R.INTERFACES | R.TRAITS); + + annotationIsClass[name] = null; + annotationIsMember[name] = null; + annotationIsGlobal[name] = null; + + for each (var interf:Object in json.traits.interfaces) + { + if("com.googlecode.flexxb.annotation.contract::IClassAnnotation" == interf) + { + annotationIsClass[name] = TRUE; + } + else if("com.googlecode.flexxb.annotation.contract::IMemberAnnotation" == interf) + { + annotationIsMember[name] = TRUE; + } + else if("com.googlecode.flexxb.annotation.contract::IGlobalAnnotation" == interf) + { + annotationIsGlobal[name] = TRUE; + } + } + + annotationMap[name] = TRUE; + annotationSerializer[name] = serializerClass != null ? new serializerClass(context) as BaseSerializer : null; + annotationClass[name] = annotationClazz; + annotationContext[name] = context; + } + } + + /** + * Get serializer associated with the annotation + * @param annotation target annotation + * @return the serializer object or null if the annotation name is not registered + */ + public function getSerializer(annotation:BaseAnnotation):BaseSerializer + { + return annotation ? annotationSerializer[annotation.annotationName] : null; + } + + public function deserialize(serializedData:XML, annotation:Annotation):* + { + if(annotation != null) + { + var serializer:BaseSerializer = annotationSerializer[annotation.annotationName]; + + if(serializer != null) + { + return serializer.deserialize(serializedData, annotation); + } + } + + return null; + } + + public function serialize(object:*, annotation:Annotation, serializedData:XML):XML + { + if(annotation != null) + { + var serializer:BaseSerializer = annotationSerializer[annotation.annotationName]; + + if(serializer != null) + { + return serializer.serialize(object, annotation, serializedData); + } + } + + return null; + } + + public function getSerializerMap():Dictionary + { + return annotationSerializer; + } + + /** + * Get the annotation representing the xml field descriptor + * @param field + * @param descriptor + * @return + */ + public function getAnnotation(descriptor:MetaDescriptor, owner:XmlClass):BaseAnnotation + { + if (descriptor != null) + { + var annotationClass:Class = annotationClass[descriptor.metadataName]; + if (annotationClass != null) + { + return new annotationClass(descriptor) as BaseAnnotation; + } + } + return null; + } + + public function getClassAnnotationName(memberMetadataName:String):String + { + if (annotationIsMember[memberMetadataName] != null) + { + var context:XmlDescriptionContext = annotationContext[memberMetadataName]; + if (context) + { + for (var key:* in annotationMap) + { + if (annotationIsClass[key] != null && annotationContext[key] == context) + { + return key; + } + } + throw new Error("No class annotation defined in the description context for metadata named " + memberMetadataName); + } + throw new Error("Could not find a description context for metadata named " + memberMetadataName + ". Please make sure it is defined within your description context."); + } + return ""; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/BaseAnnotation.as b/src/com/googlecode/flexxb/annotation/contract/BaseAnnotation.as new file mode 100644 index 0000000..ed7adc9 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/BaseAnnotation.as @@ -0,0 +1,73 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + + /** + * This is the base class for all annotations. It implements the most + * basic contract, IAnnotation, and offers the means of retrieving the + * metadata attributes and their values from the type descriptor. This + * information is passed inthe constructor via a MetaDescriptor object + * and one must override the protected methd parse in order to apply + * the necesary attributes on their own annotations. This mechanism + * makes the annotations to not require direct access to the xml + * descriptor of the type being introspected. + * @author Alexutz + * + */ + public class BaseAnnotation + { + public var annotationName:String; + + public var version:String; + + /** + * @private + */ + public function BaseAnnotation(descriptor:MetaDescriptor = null) + { + if (descriptor != null) + { + parse(descriptor); + } + } + + /** + * Set the version of the current annotation + * @param value version value + * + */ + protected final function setVersion(value:String):void + { + version = value ? value : Constants.DEFAULT; + } + + /** + * Analyze field/class descriptor to extract base informations like field's name and type. + * Override this method in subclasses to add custom parsing of values extracted from the + * annotation via the MetaDescriptor instance. + * @param descriptor MetaDescriptor instance holding the key-value pairs of existing attributes + * and their values as present in the metadata instrospection + * + */ + protected function parse(descriptor:MetaDescriptor):void + { + setVersion(descriptor.version); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/Constants.as b/src/com/googlecode/flexxb/annotation/contract/Constants.as new file mode 100644 index 0000000..2047693 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/Constants.as @@ -0,0 +1,63 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + /** + * Commonly used constants. + * @author Alexutz + */ + public class Constants + { + public static const VERSION:String = "version"; + + public static const DEFAULT:String = "default"; + /** + * Reference attribute name + */ + public static const REF:String = "reference"; + /** + * Optional attribute name + */ + public static const OPTIONAL:String = "optional"; + /** + * IgnoreOn attribute name + */ + public static const IGNORE_ON:String = "ignoreOn"; + + public static const ORDERED:String = "ordered"; + /** + * Order attribute name + */ + public static const ORDER:String = "order"; + + public static const ID:String = "idField"; + /** + * Id reference + */ + public static const IDREF:String = "idref"; + + /** + * Required reference + */ + public static const REQUIRED:String = "required"; + + public function Constants() + { + throw new Error("Can't instanciate this class. Use static accessors instead"); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/Constructor.as b/src/com/googlecode/flexxb/annotation/contract/Constructor.as new file mode 100644 index 0000000..98b52b0 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/Constructor.as @@ -0,0 +1,84 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.ClassMetaDescriptor; + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + import com.googlecode.flexxb.error.DescriptorParsingError; + + import flash.utils.Dictionary; + + /** + * Defines the class constructor. Notifies the owner XmlClass whether the + * described type has a default constructor or not. + * @author Alexutz + * + */ + public class Constructor + { + private var owner:XmlClass; + + private var fieldMap:Dictionary = new Dictionary(); + + public var parameterFields:Array = []; + + public var isDefault:Boolean = true; + + /** + * Constructor + * + */ + public function Constructor(owner:XmlClass) + { + this.owner = owner; + } + + public function hasParameterField(fieldAnnotation:XmlMember):Boolean + { + return !isDefault && fieldMap[fieldAnnotation.name.localName]; + } + + public function parse(descriptor:ClassMetaDescriptor):void + { + var arguments:Array = descriptor.getConfigItemsByName(ConstructorArgument.ANNOTATION_CONSTRUCTOR_ARGUMENT); + // multiple annotations on the same field are returned in reverse order with describeType + var args:int = 0; + for (var i:int = arguments.length - 1; i >= 0; i--) + { + var argument:ConstructorArgument = descriptor.factory.getAnnotation(arguments[i] as MetaDescriptor, owner) as ConstructorArgument; + if (!argument) + { + throw new DescriptorParsingError(owner.type, "<>", "Null argument."); + } + if (fieldMap[argument.referenceField] != null) + { + throw new DescriptorParsingError(owner.type, argument.referenceField, "Argument " + argument.referenceField + " already exists."); + } + args++; + var fieldAnnotation:XmlMember = owner.getMember(argument.referenceField); + if (!fieldAnnotation) + { + throw new DescriptorParsingError(owner.type, argument.referenceField, "Annotation for referred field does not exist"); + } + fieldMap[argument.referenceField] = fieldAnnotation; + parameterFields.push(fieldAnnotation); + } + + isDefault = args == 0; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/ConstructorArgument.as b/src/com/googlecode/flexxb/annotation/contract/ConstructorArgument.as new file mode 100644 index 0000000..6884d91 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/ConstructorArgument.as @@ -0,0 +1,69 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + + /** + * Defines a constructor argument. This annotaton is used when a class has a + * non default constructor. In order to maintain the business restrictions, FlexXB + * will determine the values of the arguments based on the received xml and call + * the constructor with those values. + *

An argument has a reference; the reference is the name of the class field + * whose value it represents. A non default constructor will most often configure + * some of the object's fields when called. Since the only available data is the + * incoming xml, arguments must specify the field the the constructor will modify + * with the received value. + *

The class field referenced in the argument must have an annotation defined + * for it + * @author Alexutz + * + */ + public class ConstructorArgument extends BaseAnnotation implements IGlobalAnnotation + { + public static const ANNOTATION_CONSTRUCTOR_ARGUMENT:String = "ConstructorArg"; + + public var referenceField:String; + + public var optional:Boolean; + + private var _owner:XmlClass; + + /** + * Constructor + * + */ + public function ConstructorArgument(descriptor:MetaDescriptor = null) + { + super(descriptor); + _owner = descriptor ? descriptor.owner : null; + annotationName = ANNOTATION_CONSTRUCTOR_ARGUMENT; + } + + public function get classAnnotation():XmlClass + { + return _owner; + } + + protected override function parse(descriptor:MetaDescriptor):void + { + super.parse(descriptor); + referenceField = descriptor.attributes[Constants.REF]; + optional = descriptor.getBoolean(Constants.OPTIONAL); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/IClassAnnotation.as b/src/com/googlecode/flexxb/annotation/contract/IClassAnnotation.as new file mode 100644 index 0000000..dcd39db --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/IClassAnnotation.as @@ -0,0 +1,32 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + /** + * This is the contract interface for a class annotation. A class annotation + * holds all the annotation structure relevant for that type, being the + * FlexXB's representation of the type. This representation is used in the + * (de)serialization process so the engine will know how to generate and + * parse xml. + * @author Alexutz + * + */ + public interface IClassAnnotation + { + + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/IGlobalAnnotation.as b/src/com/googlecode/flexxb/annotation/contract/IGlobalAnnotation.as new file mode 100644 index 0000000..5707f49 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/IGlobalAnnotation.as @@ -0,0 +1,38 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + /** + * This interface describes a metadata defined at class level, that is bound + * to the class owner metadata but defines particularities specific to the + * class itself. Good examples to this end are constructor arguments metadata + * or namespaces used by the class fields. They are not bound to a field name + * and type but they afect the class representation. + * This kind of annotations does not usually need a serializer. + * @author Alexutz + * + */ + public interface IGlobalAnnotation + { + /** + * Get a reference to the parent class annotation + * @return + * + */ + function get classAnnotation():XmlClass; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/IMemberAnnotation.as b/src/com/googlecode/flexxb/annotation/contract/IMemberAnnotation.as new file mode 100644 index 0000000..ab04651 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/IMemberAnnotation.as @@ -0,0 +1,34 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + + /** + * This contact interface defines the structure of a member annotation, + * that is, an annotation that is used only on class fields. A basic + * member annotation has a reference to its parent class annotation, + * has an access type (read, write, read/write) and can be ignored in + * one of the two stages of the engine's processing: serialization or + * deserialization. + * @author Alexutz + * + */ + public interface IMemberAnnotation + { + + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/Stage.as b/src/com/googlecode/flexxb/annotation/contract/Stage.as new file mode 100644 index 0000000..cf4bbd8 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/Stage.as @@ -0,0 +1,85 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + + /** + * This enumeration defines the preocessing directions supported by the + * FlexXBEngine: serialize and deserialize + * @author Alexutz + * + */ + public final class Stage + { + private static const SERIALIZE_NAME:String = "serialize"; + + public static const SERIALIZE:Stage = new Stage(SERIALIZE_NAME); + + private static const DESERIALIZE_NAME:String = "deserialize"; + + public static const DESERIALIZE:Stage = new Stage(DESERIALIZE_NAME); + + /** + * Obtain a Stage instance from a string value. + * @param value string representation + * @return Stage instance if the value is valid, null otherwise + * + */ + public static function fromString(value:String):Stage + { + if (value == DESERIALIZE_NAME) + { + return DESERIALIZE; + } + if (value == SERIALIZE_NAME) + { + return SERIALIZE; + } + return null; + } + + private static var initialized:Boolean = false; + { + initialized = true; + } + + private var name:String; + + /** + * @private + * + */ + public function Stage(name:String) + { + if (initialized) + { + throw new Error("Use static fields instead."); + } + this.name = name; + } + + /** + * Get a string representation of the current instance + * @return + * + */ + public function toString():String + { + return name; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/XmlArray.as b/src/com/googlecode/flexxb/annotation/contract/XmlArray.as new file mode 100644 index 0000000..24a915f --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/XmlArray.as @@ -0,0 +1,110 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + import com.googlecode.flexxb.error.DescriptorParsingError; + import avmplus.Types; + import mx.utils.StringUtil; + + /** + *

Usage: [XmlArray(alias="element", memberName="NameOfArrayElement", getFromCache="true|false", + * type="my.full.type" ignoreOn="serialize|deserialize", serializePartialElement="true|false", + * order="order_index", namespace="Namespace_Prefix", idref="true|false", + * setXsiType="true|false", version="versionName")]

+ * @author aCiobanu + * + */ + public final class XmlArray extends XmlElement + { + public static const ANNOTATION_NAME:String = "XmlArray"; + + public var memberType:Class; + + public var memberName:QName; + + public var hasMemberNamespaceRef:Boolean; + + public var memberNamespaceRef:String; + + public var memberNamespace:Namespace; + + public function XmlArray(descriptor:MetaDescriptor = null) + { + super(descriptor); + annotationName = ANNOTATION_NAME; + } + + /** + * Get the optional namespace for member + * @return + * + */ + public function setMemberNamespace(value:Namespace):void + { + memberNamespace = value; + if (memberName) + { + memberName = new QName(value, memberName.localName); + } + } + + + protected override function parse(metadata:MetaDescriptor):void + { + super.parse(metadata); + memberType = determineElementType(metadata); + memberNamespaceRef = metadata.attributes[XmlConstants.MEMBER_NAMESPACE]; + hasMemberNamespaceRef = memberNamespaceRef && StringUtil.trim(memberNamespaceRef).length > 0; + var arrayMemberName:String = metadata.attributes[XmlConstants.MEMBER_NAME]; + if (arrayMemberName) + { + var ns:Namespace = memberNamespace ? memberNamespace : nameSpace; + memberName = new QName(ns, arrayMemberName); + } + } + + private function determineElementType(metadata:MetaDescriptor):Class + { + var type:Class; + //handle the vector type. We need to check for it first as it will override settings in the member type + var classType:String = Types.getQualifiedClassName(metadata.fieldType); + if (classType.indexOf("__AS3__.vec::Vector") == 0) + { + if (classType.lastIndexOf("<") > -1) + { + classType = classType.substring(classType.lastIndexOf("<") + 1, classType.length - 1); + } + } + else + { + classType = metadata.attributes[XmlConstants.TYPE]; + } + if (classType) + { + try + { + type = Types.getDefinitionByName(classType) as Class; + } catch (e:Error) + { + throw new DescriptorParsingError(ownerClass.type, memberName.localName, "Member type <<" + classType + ">> can't be found as specified in the metadata. Make sure you spelled it correctly"); + } + } + return type; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/XmlAttribute.as b/src/com/googlecode/flexxb/annotation/contract/XmlAttribute.as new file mode 100644 index 0000000..1c70e31 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/XmlAttribute.as @@ -0,0 +1,47 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + + /** + *

Usage: [XmlAttribute(alias="attribute", ignoreOn="serialize|deserialize", order="order_index", + * namespace="NameSpace_Prefix", default="DEFAULT_VALUE", idref="true|false", version="versionName")]

+ * @author aCiobanu + * + */ + public final class XmlAttribute extends XmlMember + { + /** + * Annotation's name + */ + public static const ANNOTATION_NAME:String = "XmlAttribute"; + + /** + * Constructor + * @param descriptor xml descriptor from which to parse the data + * @param classDescriptor owner XmlClass object + * + */ + public function XmlAttribute(descriptor:MetaDescriptor = null) + { + super(descriptor); + + annotationName = ANNOTATION_NAME; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/XmlClass.as b/src/com/googlecode/flexxb/annotation/contract/XmlClass.as new file mode 100644 index 0000000..d7e6e6a --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/XmlClass.as @@ -0,0 +1,244 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.ClassMetaDescriptor; + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + import com.googlecode.flexxb.error.DescriptorParsingError; + import flash.utils.Dictionary; + import mx.collections.ISort; + import mx.collections.SortField; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * + *

Usage: [XmlClass(alias="MyClass", useNamespaceFrom="elementFieldName", + * idField="idFieldName", prefix="my", uri="http://www.your.site.com/schema/", + * defaultValueField="fieldName", ordered="true|false", version="versionName")]

+ * @author aCiobanu + * + */ + public final class XmlClass extends Annotation implements IClassAnnotation + { + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.annotation.contract.XmlClass"); + + public static const ANNOTATION_NAME:String = "XmlClass"; + + public static const SORT:Array = [new SortField("alias", true, false, false)]; + + [ArrayElementType("com.googlecode.flexxb.annotation.contract.XmlMember")] + public var members:Array = []; + + private var _sort:ISort; + + private var id:String; + + public var idField:XmlMember; + + private var defaultValue:String; + + public var valueField:Annotation; + + public var childNameSpaceFieldName:String; + + public var ordered:Boolean; + + public var useOwnNamespace:Boolean; + + public var constructor:Constructor; + + private var namespaces:Dictionary = new Dictionary(); + + private var membersMap:Dictionary = new Dictionary(); + + public function XmlClass(descriptor:ClassMetaDescriptor = null) + { + constructor = new Constructor(this); + if(descriptor != null) + { + descriptor.owner = this; + } + + super(descriptor); + annotationName = ANNOTATION_NAME; + } + + public function getMember(memberFieldName:String):XmlMember + { + return membersMap[memberFieldName]; + } + + public function getAdditionalSortFields():Array + { + return SORT.concat(); + } + + protected override function parse(descriptor:MetaDescriptor):void + { + super.parse(descriptor); + + var desc:ClassMetaDescriptor = descriptor as ClassMetaDescriptor; + id = desc.attributes[Constants.ID]; + childNameSpaceFieldName = desc.attributes[XmlConstants.USE_CHILD_NAMESPACE]; + useOwnNamespace = childNameSpaceFieldName == null || childNameSpaceFieldName.length == 0; + ordered = desc.getBoolean(Constants.ORDERED); + defaultValue = desc.attributes[XmlConstants.VALUE]; + + processNamespaces(desc); + + setNameSpace(getNamespace(descriptor)); + + for each(var meta:MetaDescriptor in desc.members) + { + addMember(desc.factory.getAnnotation(meta, this) as XmlMember); + } + + constructor.parse(desc); + + memberAddFinished(); + } + + private function addMember(annotation:XmlMember):void + { + if (annotation && !isFieldRegistered(annotation)) + { + if (annotation.hasNamespaceRef) + { + annotation.setNameSpace(getRegisteredNamespace(annotation.namespaceRef)); + } + else + { + annotation.setNameSpace(nameSpace); + } + if (annotation is XmlArray) + { + var xmlArray:XmlArray = XmlArray(annotation); + if (xmlArray.hasMemberNamespaceRef) + { + xmlArray.setMemberNamespace(getRegisteredNamespace(xmlArray.memberNamespaceRef)); + } + } + members.push(annotation); + membersMap[annotation.name.localName] = annotation; + if (annotation.name.localName == id) + { + idField = annotation; + } + if (annotation.alias == defaultValue) + { + valueField = annotation; + //set member default value + annotation.isDefaultValue = true; + } + } + } + + private function memberAddFinished():void + { + //Flex SDK 4 hotfix: we need to put the default field first, if it exists, + // otherwise the default text will be added as a child of a previous element + var member:XmlMember; + var length:Number = members.length; + for (var i:int = 0; i < length; i++) + { + member = members[i] as XmlMember; + if (member.isDefaultValue) + { + members.splice(i, 1); + members.splice(0, 0, member); + break; + } + } + } + + private function processNamespaces(descriptor:ClassMetaDescriptor):void + { + var nss:Array = descriptor.getConfigItemsByName(XmlConstants.ANNOTATION_NAMESPACE); + if (nss.length > 0) + { + var ns:Namespace; + for each(var nsDesc:MetaDescriptor in nss) + { + ns = getNamespace(nsDesc); + namespaces[ns.prefix] = ns; + } + } + } + + private function getRegisteredNamespace(ref:String):Namespace + { + var namespace:Namespace = namespaces[ref]; + if (!namespace) + { + throw new DescriptorParsingError(type, "", "Namespace reference <<" + ref + ">> could not be found. Make sure you typed the prefix correctly and the namespace is registered as annotation of the containing class."); + } + return namespace as Namespace; + } + + private function getNamespace(descriptor:MetaDescriptor):Namespace + { + var prefix:String = descriptor.attributes[XmlConstants.NAMESPACE_PREFIX]; + var uri:String = descriptor.attributes[XmlConstants.NAMESPACE_URI]; + if (uri == null || uri.length == 0) + { + try + { + if (prefix) + { + return getRegisteredNamespace(prefix); + } + } catch (e:Error) + { + LOG.error("getRegisteredNamespace failed", e.getStackTrace()); + } + return null; + } + else if (prefix != null && prefix.length > 0) + { + return new Namespace(prefix, uri); + } + return new Namespace(uri); + } + + private function isFieldRegistered(annotation:Annotation):Boolean + { + for each (var member:Annotation in members) + { + if (member.name == annotation.name) + { + return true; + } + } + return false; + } + + public function get sort():ISort + { + return _sort; + } + + public function set sort(value:ISort):void + { + _sort = value; + if(sort != null) + { + sort.sort(members); + } + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/XmlConstants.as b/src/com/googlecode/flexxb/annotation/contract/XmlConstants.as new file mode 100644 index 0000000..103869d --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/XmlConstants.as @@ -0,0 +1,104 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.annotation.contract +{ + /** + * @private + * @author Alexutz + * + */ + public class XmlConstants extends Constants + { + + public static const ANNOTATION_NAMESPACE:String = "Namespace"; + /** + * + */ + public static const ALIAS:String = "alias"; + /** + * + */ + public static const ALIAS_ANY:String = "*"; + /** + * Namespace prefix + */ + public static const NAMESPACE_PREFIX:String = "prefix"; + /** + * + */ + public static const NAMESPACE:String = "namespace"; + /** + * Namespace uri + */ + public static const NAMESPACE_URI:String = "uri"; + /** + * + */ + public static const USE_CHILD_NAMESPACE:String = "useNamespaceFrom"; + /** + * + */ + public static const VALUE:String = "defaultValueField"; + /** + * Path separator used for defining virtual paths in the alias + */ + public static const ALIAS_PATH_SEPARATOR:String = "/"; + /** + * + */ + public static const NAMESPACE_REF:String = "namespace"; + /** + * SerializePartialElement attribute name + */ + public static const SERIALIZE_PARTIAL_ELEMENT:String = "serializePartialElement"; + /** + * GetFromCache attribute name + */ + public static const GET_FROM_CACHE:String = "getFromCache"; + /** + * + */ + public static const GET_RUNTIME_TYPE:String = "getRuntimeType"; + /** + * + */ + public static const SET_XSI_TYPE:String = "setXsiType"; + /** + * + */ + public static const NILLABLE:String = "nillable"; + + /** + * + */ + public static const WRAP_CDATA:String = "wrapCDATA"; + + /** + * + */ + public static const TYPE:String = "type"; + /** + * + */ + public static const MEMBER_NAME:String = "memberName"; + /** + * + */ + public static const MEMBER_NAMESPACE:String = "memberNamespace"; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/XmlElement.as b/src/com/googlecode/flexxb/annotation/contract/XmlElement.as new file mode 100644 index 0000000..737e888 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/XmlElement.as @@ -0,0 +1,70 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + + /** + * Usage: [XmlElement(alias="element", getFromCache="true|false", + * ignoreOn="serialize|deserialize", serializePartialElement="true|false", + * order="order_index", getRuntimeType="true|false", namespace="Namespace_Prefix", + * default="DEFAULT_VALUE", idref="true|false", setXsiType="true|false", + * version="versionName")] + * @author aCiobanu + * + */ + public class XmlElement extends XmlMember + { + public static const ANNOTATION_NAME:String = "XmlElement"; + + public var serializePartialElement:Boolean; + + public var getFromCache:Boolean; + + public var getRuntimeType:Boolean; + + public var setXsiType:Boolean; + + public var nillable:Boolean; + + public var wrapCDATA:Boolean; + + /** + * Constructor + * @param descriptor + * @param xmlClass + * + */ + public function XmlElement(descriptor:MetaDescriptor = null) + { + super(descriptor); + annotationName = ANNOTATION_NAME; + } + + protected override function parse(metadata:MetaDescriptor):void + { + super.parse(metadata); + serializePartialElement = metadata.getBoolean(XmlConstants.SERIALIZE_PARTIAL_ELEMENT); + getFromCache = metadata.getBoolean(XmlConstants.GET_FROM_CACHE); + getRuntimeType = metadata.getBoolean(XmlConstants.GET_RUNTIME_TYPE); + setXsiType = metadata.getBoolean(XmlConstants.SET_XSI_TYPE); + nillable = metadata.getBoolean(XmlConstants.NILLABLE); + wrapCDATA = metadata.getBoolean(XmlConstants.WRAP_CDATA); + isRequired = isRequired || nillable; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/XmlMember.as b/src/com/googlecode/flexxb/annotation/contract/XmlMember.as new file mode 100644 index 0000000..045f357 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/XmlMember.as @@ -0,0 +1,161 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + import com.googlecode.flexxb.error.DescriptorParsingError; + + import mx.utils.StringUtil; + + /** + * Defines a member of an XmlClass, that is, a field of the class definition. + * The XmlMember is base for XmlAttribute and XmlElement since field values can + * be rendered as XML in the form of attributes or elements. + *

A member's alias can define "virtual paths". Virtual paths allow definition + * of complex xml structures for a field without complicating the model design. Thus, + * structures can be present in the xml just by adding vistual paths in the alias + * definition of a member. + *

Example: Lets assume the xml representation looks like: + *

+     * <myPathTester>
+     *      <anotherSub attTest="Thu Mar 19 15:49:32 GMT+0200 2009"/>
+     *      This is Default!!!
+     *      <subObject>
+     *        <id>
+     *          2
+     *        </id>
+     *        <subSubObj>
+     *          <ref>
+     *            ReferenceTo
+     *          </ref>
+     *        </subSubObj>
+     *      </subObject>
+     *    </myPathTester>
+     * 
+ *

This would normally translate itself in about 4 model classes. Using virtual paths, one can describe it in just one model class: + *

+     * [XmlClass(alias="myPathTester", defaultValueField="defaultTest")]
+     *    public class XmlPathObject
+     *    {
+	 *		[XmlElement(alias="subObject/id")]
+	 *		public var identity : Number = 2;
+	 *		[XmlElement(alias="subObject/subSubObj/ref")]
+	 *		public var reference : String = "ReferenceTo";
+	 *		[XmlArray(alias="subObject/list")]
+	 *		public var list : Array;
+	 *		[XmlAttribute(alias="anotherSub/attTest")]
+	 *		public var test : Date = new Date();
+	 *		[XmlElement()]
+	 *		public var defaultTest : String = "This is Default!!!"
+	 *
+	 *		public function XmlPathObject()
+	 *		{
+	 *		}
+	 *	}
+     * 
+ * @author aCiobanu + * + */ + public class XmlMember extends Annotation implements IMemberAnnotation + { + public var ignoreOn:Stage; + + public var order:Number; + + public var classAnnotation:XmlClass; + + public var ownerClass:XmlClass; + + public var accessor:AccessorType; + + public var defaultSetValue:String; + + public var isIDRef:Boolean; + + public var hasNamespaceRef:Boolean; + + public var readOnly:Boolean; + + public var writeOnly:Boolean; + + public var isRequired:Boolean; + + public var isDefaultValue:Boolean; + + /** + * Constructor + * @param descriptor xml descriptor of the class field + * @param _class owner XmlClass entity + * + */ + public function XmlMember(descriptor:MetaDescriptor = null) + { + super(descriptor); + } + + protected override function parse(descriptor:MetaDescriptor):void + { + classAnnotation = descriptor.owner as XmlClass; + isDefaultValue = classAnnotation && classAnnotation.valueField == this; + ownerClass = descriptor.owner as XmlClass; + super.parse(descriptor); + accessor = descriptor.fieldAccess; + readOnly = accessor.isReadOnly(); + writeOnly = accessor.isWriteOnly(); + hasNamespaceRef = namespaceRef && StringUtil.trim(namespaceRef).length > 0; + ignoreOn = Stage.fromString(descriptor.attributes[Constants.IGNORE_ON]); + setOrder(descriptor.attributes[Constants.ORDER]); + defaultSetValue = descriptor.attributes[Constants.DEFAULT]; + isIDRef = descriptor.getBoolean(Constants.IDREF); + isRequired = descriptor.getBoolean(Constants.REQUIRED); + } + + protected override function setAlias(value:String):void + { + super.setAlias(value); + if (classAnnotation && classAnnotation.isPath) + { + var path:Array = classAnnotation.qualifiedPathElements; + if (!qualifiedPathElements) + { + qualifiedPathElements = []; + } + qualifiedPathElements.unshift(classAnnotation.xmlName); + for (var i:int = path.length - 1; i > 0; i--) + { + qualifiedPathElements.unshift(path[i]); + } + } + } + + protected function setOrder(value:String):void + { + if (value) + { + var nr:Number; + try + { + nr = Number(value); + } catch (error:Error) + { + throw new DescriptorParsingError(ownerClass.type, name.localName, "The order attribute of the annotation is invalid as number"); + } + order = nr; + } + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/contract/XmlNamespace.as b/src/com/googlecode/flexxb/annotation/contract/XmlNamespace.as new file mode 100644 index 0000000..d9f5a43 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/contract/XmlNamespace.as @@ -0,0 +1,52 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation.contract +{ + import com.googlecode.flexxb.annotation.parser.MetaDescriptor; + + /** + * + * @author Alexutz + * + */ + public class XmlNamespace extends BaseAnnotation implements IGlobalAnnotation + { + public var uri:String; + + public var prefix:String; + + private var _owner:XmlClass; + + public function XmlNamespace(descriptor:MetaDescriptor = null) + { + super(descriptor); + annotationName = XmlConstants.ANNOTATION_NAMESPACE; + } + + public function get classAnnotation():XmlClass + { + return _owner; + } + + protected override function parse(descriptor:MetaDescriptor):void + { + super.parse(descriptor); + uri = descriptor.attributes[XmlConstants.NAMESPACE_URI]; + prefix = descriptor.attributes[XmlConstants.NAMESPACE_PREFIX]; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/parser/ClassMetaDescriptor.as b/src/com/googlecode/flexxb/annotation/parser/ClassMetaDescriptor.as new file mode 100644 index 0000000..4799cce --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/parser/ClassMetaDescriptor.as @@ -0,0 +1,65 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.annotation.parser +{ + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.XmlClass; + + /** + * @private + * @author Alexutz + * + */ + public final class ClassMetaDescriptor extends MetaDescriptor + { + [ArrayElementType("com.googlecode.flexxb.annotation.contract.IGlobalAnnotation")] + public var config:Array; + + [ArrayElementType("com.googlecode.flexxb.annotation.contract.XmlMember")] + public var members:Array; + + public function ClassMetaDescriptor(factory:AnnotationFactory) + { + super(factory); + members = []; + config =[]; + } + + public override function set owner(value:XmlClass):void + { + super.owner = value; + for each(var member:MetaDescriptor in members) + { + member.owner = value; + } + } + + public function getConfigItemsByName(annotationName:String):Array + { + var result:Array = []; + for each(var descriptor:MetaDescriptor in config) + { + if (descriptor.metadataName == annotationName) + { + result.push(descriptor); + } + } + return result; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/parser/MetaDescriptor.as b/src/com/googlecode/flexxb/annotation/parser/MetaDescriptor.as new file mode 100644 index 0000000..1a8ca97 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/parser/MetaDescriptor.as @@ -0,0 +1,87 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.annotation.parser +{ + import com.googlecode.flexxb.annotation.contract.AccessorType; + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.Constants; + import com.googlecode.flexxb.annotation.contract.XmlClass; + + /** + * @private + * @author Alexutz + * + */ + public class MetaDescriptor + { + public var metadataName:String; + + public var fieldName:QName; + + public var fieldType:Class; + + public var fieldAccess:AccessorType; + + public var attributes:Object; + + private var _owner:XmlClass; + + private var _factory:AnnotationFactory; + + public function MetaDescriptor(factory:AnnotationFactory) + { + attributes = {}; + _factory = factory; + } + + public final function get factory():AnnotationFactory + { + return _factory; + } + + public function get owner():XmlClass + { + return _owner; + } + + public function set owner(value:XmlClass):void + { + _owner = value; + } + + public function get version():String + { + return attributes[Constants.VERSION] ? attributes[Constants.VERSION] : Constants.DEFAULT; + } + + public function getBoolean(name:String):Boolean + { + return attributes[name] == "true"; + } + + public function getInt(name:String):Number + { + return Number(attributes[name]); + } + + public function getString(name:String):String + { + return attributes[name] as String; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/annotation/parser/MetaParser.as b/src/com/googlecode/flexxb/annotation/parser/MetaParser.as new file mode 100644 index 0000000..5ea5459 --- /dev/null +++ b/src/com/googlecode/flexxb/annotation/parser/MetaParser.as @@ -0,0 +1,206 @@ +package com.googlecode.flexxb.annotation.parser +{ + import com.googlecode.flexxb.annotation.contract.AccessorType; + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.error.DescriptorParsingError; + import avmplus.Types; + + import mx.collections.Sort; + import mx.collections.SortField; + + public final class MetaParser + { + private var factory:AnnotationFactory; + private var name:QName; + private var type:Class; + + public function MetaParser(factory:AnnotationFactory) + { + this.factory = factory; + } + + /** + * + * @param json + * @return array of IClassAnnotation implementor instances, one for each version dicovered in the descriptor + * @see com.googlecode.flexxb.annotation.IClassAnnotation + * @throws com.googlecode.flexxb.error.DescriptorParsingError + * + */ + public function parseDescriptor(json:Object):Array + { + var classes:Object = {}; + processClassDescriptors(json, classes); + var field:Object; + for each (field in json.traits.variables) + { + processMemberDescriptors(field, classes, name, type); + } + for each (field in json.traits.accessors) + { + processMemberDescriptors(field, classes, name, type); + } + var result:Array = []; + var descriptor:ClassMetaDescriptor; + var classAnnotation:XmlClass; + for (var key:* in classes) + { + descriptor = classes[key]; + classAnnotation = factory.getAnnotation(descriptor, null) as XmlClass; + if (classAnnotation.ordered) + { + var sort:Sort = new Sort(); + sort.fields = [new SortField("order", false, false, true)].concat(classAnnotation.getAdditionalSortFields()); + classAnnotation.sort = sort; + } + result.push(classAnnotation); + } + name = null; + type = null; + return result; + } + + private function processClassDescriptors(json:Object, classMap:Object):void + { + var classType:String = json.name; + name = new QName(null, classType.substring(classType.lastIndexOf(":") + 1)); + type = Types.getDefinitionByName(classType) as Class; + var metas:Array = json.traits.metadata; + var descriptors:Array = []; + var descriptor:MetaDescriptor; + for each(var meta:Object in metas) + { + descriptor = parseMetadata(meta); + if (!descriptor) + { + continue; + } + if (factory.isMemberAnnotation(descriptor.metadataName)) + { + throw new DescriptorParsingError(type, "", "Member type metadata found on class level. You should only define class and global metadatas at class level. Class metadata representant must implement IClassAnnotation; Global metadata representant must implement IGlobalAnnotation"); + } + descriptor.fieldName = name; + descriptor.fieldType = type; + //we have global anotations + if (factory.isGlobalAnnotation(descriptor.metadataName)) + { + descriptors.push(descriptor); + continue; + } + //we have class annotations + if (classMap[descriptor.version]) + { + throw new DescriptorParsingError(type, "", "Two class type metadatas found with the same version (" + descriptor.version + ")"); + } + classMap[descriptor.version] = descriptor; + } + var owner:ClassMetaDescriptor; + + //we need to assign the global descriptors to their proper class annotations + for each(descriptor in descriptors) + { + owner = classMap[descriptor.version]; + if (owner) + { + owner.config.push(descriptor); + } + else + { + throw new DescriptorParsingError(owner.fieldType, descriptor.fieldName.localName, "Could not find a class annotation with the version" + meta.version); + } + } + } + + private function processMemberDescriptors(field:Object, classMap:Object, className:QName, classType:Class):void + { + var descriptors:Array = parseField(field); + var owner:ClassMetaDescriptor; + var ownerName:String; + for each(var meta:MetaDescriptor in descriptors) + { + owner = classMap[meta.version]; + if (owner == null && (ownerName = getOwnerName(meta))) + { + owner = new ClassMetaDescriptor(factory); + owner.metadataName = ownerName; + owner.fieldType = classType; + owner.fieldName = className; + classMap[meta.version] = owner; + } + if (owner) + { + owner.members.push(meta); + } + else + { + throw new DescriptorParsingError(classType, meta.fieldName.localName, "Could not find a class annotation with the version" + meta.version); + } + } + } + + public function parseMetadata(json:Object):MetaDescriptor + { + var metadataName:String = json.name; + var descriptor:MetaDescriptor; + //Need to make sure we're not parsing any bogus annotation + if (factory.isRegistered(metadataName)) + { + descriptor = getDescriptorInstance(metadataName); + descriptor.metadataName = json.name; + for each(var argument:Object in json.value) + { + descriptor.attributes[argument.key] = argument.value; + } + } + return descriptor; + } + + private function getDescriptorInstance(metadataName:String):MetaDescriptor + { + if (factory.isClassAnnotation(metadataName)) + { + return new ClassMetaDescriptor(factory); + } + return new MetaDescriptor(factory); + } + + public function parseField(json:Object):Array + { + var descriptors:Array = []; + var name:QName = new QName(json.uri ? json.uri : "", json.name); + var accessType:AccessorType = AccessorType.fromString(json.access); + var type:Class; + try + { + type = Types.getDefinitionByName(json.type) as Class; + } catch (e:Error) + { + throw e; + } + var metas:Array = json.metadata; + var descriptor:MetaDescriptor; + for each(var meta:Object in metas) + { + descriptor = parseMetadata(meta); + if (descriptor) + { + if (!factory.isMemberAnnotation(descriptor.metadataName)) + { + throw new DescriptorParsingError(type, "", "Non-Member type metadata found on field level. You should only define class and global metadatas at class level. The member metadata must implement IMemberAnnotation."); + } + descriptor.fieldName = name; + descriptor.fieldType = type; + descriptor.fieldAccess = accessType; + descriptors.push(descriptor); + } + } + return descriptors; + } + + private function getOwnerName(meta:MetaDescriptor):String + { + return factory.getClassAnnotationName(meta.metadataName); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/AccessorTypeConverter.as b/src/com/googlecode/flexxb/api/AccessorTypeConverter.as new file mode 100644 index 0000000..f8347d5 --- /dev/null +++ b/src/com/googlecode/flexxb/api/AccessorTypeConverter.as @@ -0,0 +1,52 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.AccessorType; + import com.googlecode.flexxb.converter.IConverter; + + /** + * @private + * @author Alexutzutz + * + */ + public final class AccessorTypeConverter implements IConverter + { + public function AccessorTypeConverter() + { + } + + public function get type():Class + { + return AccessorType; + } + + public function toString(object:Object):String + { + if (object is AccessorType) + { + return AccessorType(object).toString(); + } + return ""; + } + + public function fromString(value:String):Object + { + return AccessorType.fromString(value); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/FxApiWrapper.as b/src/com/googlecode/flexxb/api/FxApiWrapper.as new file mode 100644 index 0000000..1e17512 --- /dev/null +++ b/src/com/googlecode/flexxb/api/FxApiWrapper.as @@ -0,0 +1,34 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + + [XmlClass(alias="FlexXBAPI")] + /** + * Wrapper holding the class descriptors specified in the xml api descriptor file + * @author Alexutz + * + */ + public class FxApiWrapper + { + [XmlArray(alias="Descriptors", getRuntimeType="true")] + [ArrayElementType("com.googlecode.flexxb.api.FxClass")] + public var descriptors:Array; + [XmlAttribute] + public var version:Number; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/FxClass.as b/src/com/googlecode/flexxb/api/FxClass.as new file mode 100644 index 0000000..9045883 --- /dev/null +++ b/src/com/googlecode/flexxb/api/FxClass.as @@ -0,0 +1,163 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.Constants; + import flash.utils.Dictionary; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * API wrapper for a class type. Allows programatically defining all the + * elements that would normally be specified via annotations. + * @author Alexutz + * + */ + public class FxClass implements IFxMetaProvider + { + private static const log:ILogger = Log.getLogger("com.googlecode.flexxb.api.FxClass"); + + [XmlAttribute] + public var version:String = ""; + + [XmlArray(alias="ConstructorArguments", type="com.googlecode.flexxb.api.FxConstructorArgument")] + [ArrayElementType("com.googlecode.flexxb.api.FxConstructorArgument")] + public var constructorArguments:Array; + + [XmlAttribute] + public var type:Class; + + private var _members:Array = []; + + /** + * Constructor + * @param type class type + * @param alias class alias + */ + public function FxClass(type:Class = null) + { + this.type = type; + } + + [XmlArray(alias="Members", getRuntimeType="true")] + [ArrayElementType("com.googlecode.flexxb.api.FxMember")] + public final function get members():Array + { + return _members; + } + + public final function set members(value:Array):void + { + _members = value; + for each(var member:FxMember in value) + { + member.owner = this; + onMemberAdded(member); + } + } + + public function getMetadataName():String + { + return ""; + } + + public function getMappingValues():Dictionary + { + var values:Dictionary = new Dictionary(); + values[Constants.VERSION] = version; + return values; + } + + /** + * + * @return + * + */ + public function getGlobalAnnotations():Array + { + return null; + } + + /** + * Add a constructor argument. Arguments are used in order to correctly instantiate objects upon deserialization + * taking into account default and parameterized constructor. + * @param fieldName field name + * @param optional Flag signaling whether the argument is optional or not (eg. default valued parameters) + * + */ + public final function addArgument(fieldName:String, optional:Boolean = false):void + { + if (!constructorArguments) + { + constructorArguments = []; + } + constructorArguments.push(new FxConstructorArgument(fieldName, optional)); + } + + /** + * + * @param name + * @return + * + */ + protected final function hasMember(name:String):Boolean + { + for each (var member:FxMember in members) + { + if (member.fieldName == name) + { + return true; + } + } + return false; + } + + /** + * Add a class member + * @param member class member (subclass of FxMember) + * + */ + public final function addMember(member:FxMember):void + { + if (hasMember(member.fieldName)) + { + throw new Error("Field <" + member.fieldName + "> has already been defined for class type " + type); + } + member.owner = this; + members.push(member); + onMemberAdded(member); + } + + /** + * Get string representation of the current instance + * @return string representing the current instance + */ + public function toString():String + { + return "Class[type: " + type + "]"; + } + + /** + * + * @param member + * + */ + protected function onMemberAdded(member:FxMember):void + { + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/FxConstructorArgument.as b/src/com/googlecode/flexxb/api/FxConstructorArgument.as new file mode 100644 index 0000000..5aff301 --- /dev/null +++ b/src/com/googlecode/flexxb/api/FxConstructorArgument.as @@ -0,0 +1,75 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.Constants; + import com.googlecode.flexxb.error.ApiError; + + import flash.utils.Dictionary; + + [XmlClass(alias="Argument")] + [ConstructorArg(reference="reference")] + /** + * A constructor argument is a way to say to the FlexXB engine that objects of a certain type + * need a special way to be instantiated in the deserialization stage. A constructor argument + * is linked to a class field. Usually, when having parameterized arguments, in the constructor + * these values are mapped to specific fields within the object. + * @author Alexutz + * + */ + public class FxConstructorArgument implements IFxMetaProvider + { + [XmlAttribute] + public var reference:String; + + [XmlAttribute] + public var optional:Boolean; + + /** + * Constructor + * @param reference name of the class field this argument references + * @param optional Flag signaling whether this argument is optional or not in the constructor call + */ + public function FxConstructorArgument(reference:String = null, optional:Boolean = false) + { + this.reference = reference; + this.optional = optional; + } + + public function getMetadataName():String + { + return "ConstructorArg"; + } + + public function getMappingValues():Dictionary + { + var values:Dictionary = new Dictionary(); + values[Constants.REF] = reference; + values[Constants.OPTIONAL] = optional; + return values; + } + + /** + * Get the string representation of the current instance + * @return String instance + */ + public function toString():String + { + return "Argument[reference: " + reference + ", optional:" + optional + "]"; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/FxField.as b/src/com/googlecode/flexxb/api/FxField.as new file mode 100644 index 0000000..fe02245 --- /dev/null +++ b/src/com/googlecode/flexxb/api/FxField.as @@ -0,0 +1,71 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.AccessorType; + + import mx.utils.StringUtil; + + [XmlClass(alias="Field")] + [ConstructorArg(reference="name")] + [ConstructorArg(reference="type")] + /** + * + * @author Alexutz + * + */ + public class FxField + { + [XmlAttribute] + public var name:String; + + [XmlAttribute] + public var type:Class; + + [XmlAttribute] + public var accessType:AccessorType; + + /** + * + * @param name + * @param type + * @param accessType + */ + public function FxField(name:String = null, type:Class = null, accessType:AccessorType = null) + { + this.name = name; + this.type = type; + if (accessType) + { + this.accessType = accessType; + } + else + { + this.accessType = AccessorType.READ_WRITE; + } + } + + /** + * Get string representation of the current instance + * @return string representing the current instance + */ + public function toString():String + { + return "Field[name: " + name + ", type:" + type + ", access: " + accessType + "]"; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/FxMember.as b/src/com/googlecode/flexxb/api/FxMember.as new file mode 100644 index 0000000..54e6aa9 --- /dev/null +++ b/src/com/googlecode/flexxb/api/FxMember.as @@ -0,0 +1,98 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.AccessorType; + import com.googlecode.flexxb.annotation.contract.Constants; + import com.googlecode.flexxb.annotation.contract.Stage; + import com.googlecode.flexxb.error.ApiError; + + import flash.utils.Dictionary; + + import mx.logging.ILogger; + import mx.logging.Log; + + use namespace flexxb_api_internal; + + /** + * API member annotation wrapper. This is the base for member annotation + * API description. It references the field from the parent type and base + * attributes that all members will share: version and ignore flags.
+ * All member annotations have a version in order to handle different + * representations of the same object that may appear as appplication + * develoment evolves. Also, some fields may be ignored in different stages + * of the processing: serialize or deserialize. + * @author Alexutz + * + */ + public class FxMember implements IFxMetaProvider + { + private static const log:ILogger = Log.getLogger("com.googlecode.flexxb.api.FxMember"); + + [XmlAttribute] + public var ignoreOn:Stage = null; + + [XmlAttribute] + public var version:String = ""; + + [XmlElement(alias="*")] + public var field:FxField; + + internal var owner:FxClass; + + public function FxMember(field:FxField = null) + { + this.field = field; + } + + public function get fieldName():String + { + return field.name; + } + + public function get fieldType():Class + { + return field.type; + } + + public function get fieldAccessType():AccessorType + { + return field.accessType; + } + + public function getMetadataName():String + { + return ""; + } + + public function getMappingValues():Dictionary + { + var values:Dictionary = new Dictionary(); + if (ignoreOn) + { + values[Constants.IGNORE_ON] = ignoreOn; + } + values[Constants.VERSION] = version; + return values; + } + + protected final function getOwner():FxClass + { + return owner; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/IFlexXBApi.as b/src/com/googlecode/flexxb/api/IFlexXBApi.as new file mode 100644 index 0000000..ab7246b --- /dev/null +++ b/src/com/googlecode/flexxb/api/IFlexXBApi.as @@ -0,0 +1,61 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import avmplus.RMember; + import avmplus.RObject; + + /** + * This interface defines the api structure and access points + * @author Alexutz + * + */ + public interface IFlexXBApi + { + /** + * Register a type descriptor that is defined by the api components. This is especially + * useful when not having access to source code. + * @param apiDescriptor + * + */ + function processTypeDescriptor(apiDescriptor:FxClass):void; + + /** + * Register the type descriptors by the mmeans of an xml file. The content is converted + * to api components then they are processed to register the type described in the xml file. + * @param xml + * + */ + function processDescriptorsFromXml(xml:XML):void; + + /** + * + * @param apiClass + * @return + * + */ + function buildTypeDescriptor(apiClass:FxClass):RObject; + + /** + * + * @param member + * @return + * + */ + function buildFieldDescriptor(member:FxMember):RMember; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/IFxMetaProvider.as b/src/com/googlecode/flexxb/api/IFxMetaProvider.as new file mode 100644 index 0000000..b2079d2 --- /dev/null +++ b/src/com/googlecode/flexxb/api/IFxMetaProvider.as @@ -0,0 +1,45 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import flash.utils.Dictionary; + + /** + * + * @author User + * + */ + public interface IFxMetaProvider + { + /** + * Get the name of the metadata this class describes + * @return metadata name + * + */ + function getMetadataName():String; + + /** + * Get a dictionary with key-value pairs representing the + * annotation attribute names and their values. This map + * is used by the API to construct the actual descriptors + * used by FlexXB to process the objects and serialized data + * @return Dictionary instance + * + */ + function getMappingValues():Dictionary; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/StageXmlConverter.as b/src/com/googlecode/flexxb/api/StageXmlConverter.as new file mode 100644 index 0000000..642b536 --- /dev/null +++ b/src/com/googlecode/flexxb/api/StageXmlConverter.as @@ -0,0 +1,45 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.Stage; + import com.googlecode.flexxb.converter.IConverter; + + /** + * @private + * @author Alexutz + * + */ + public class StageXmlConverter implements IConverter + { + + public function get type():Class + { + return Stage; + } + + public function toString(object:Object):String + { + return (object as Stage).toString(); + } + + public function fromString(value:String):Object + { + return Stage.fromString(value); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/XmlApiArray.as b/src/com/googlecode/flexxb/api/XmlApiArray.as new file mode 100644 index 0000000..bb0e8c8 --- /dev/null +++ b/src/com/googlecode/flexxb/api/XmlApiArray.as @@ -0,0 +1,108 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.AccessorType; + import avmplus.Types; + + import flash.utils.Dictionary; + + [XmlClass(alias="XmlArray")] + [ConstructorArg(reference="field")] + [ConstructorArg(reference="alias")] + public class XmlApiArray extends XmlApiElement + { + public static const INCOMING_XML_NAME:String = "XmlArray"; + + public static function create(name:String, type:Class, accessType:AccessorType = null, alias:String = null):XmlApiArray + { + var field:FxField = new FxField(name, type, accessType); + var array:XmlApiArray = new XmlApiArray(field, alias); + return array; + } + + [XmlAttribute] + public var memberName:String; + + [XmlAttribute] + public var memberType:Class; + + protected var _memberNameSpace:XmlApiNamespace; + + public function XmlApiArray(field:FxField = null, alias:String = null) + { + super(field, alias); + } + + [XmlElement] + public final function get memberNameSpace():XmlApiNamespace + { + return _memberNameSpace; + } + + public final function set memberNameSpace(value:XmlApiNamespace):void + { + _memberNameSpace = value; + if (getOwner()) + { + if (value) + { + _memberNameSpace = XmlApiClass(getOwner()).addNamespace(value); + } + else + { + XmlApiClass(getOwner()).removeNamespace(value); + } + } + } + + public function setMemberNamespace(ns:Namespace):void + { + memberNameSpace = XmlApiNamespace.create(ns); + } + + public override function getMetadataName():String + { + return XmlArray.ANNOTATION_NAME; + } + + public override function getMappingValues():Dictionary + { + var values:Dictionary = super.getMappingValues(); + if (memberName) + { + values[XmlConstants.MEMBER_NAME] = memberName; + } + if (memberType is Class) + { + values[XmlConstants.TYPE] = Types.getQualifiedClassName(memberType); + } + return values; + } + + /** + * Get string representation of the current instance + * @return string representing the current instance + */ + public override function toString():String + { + return "Array[field: " + fieldName + ", type:" + fieldType + "]"; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/XmlApiAttribute.as b/src/com/googlecode/flexxb/api/XmlApiAttribute.as new file mode 100644 index 0000000..e0c1602 --- /dev/null +++ b/src/com/googlecode/flexxb/api/XmlApiAttribute.as @@ -0,0 +1,69 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.AccessorType; + + [XmlClass(alias="XmlAttribute")] + [ConstructorArg(reference="field")] + [ConstructorArg(reference="alias")] + public class XmlApiAttribute extends XmlApiMember + { + public static const INCOMING_XML_NAME:String = "XmlAttribute"; + + /** + * + * @param name + * @param type + * @param accessType + * @param alias + * @return + * + */ + public static function create(name:String, type:Class, accessType:AccessorType = null, alias:String = null):XmlApiAttribute + { + var field:FxField = new FxField(name, type, accessType); + var attribute:XmlApiAttribute = new XmlApiAttribute(field, alias); + return attribute; + } + + /** + * + * @param field + * @param alias + * + */ + public function XmlApiAttribute(field:FxField = null, alias:String = null) + { + super(field, alias); + } + + public override function getMetadataName():String + { + return "XmlAttribute"; + } + + /** + * Get string representation of the current instance + * @return string representing the current instance + */ + public function toString():String + { + return "XmlAttribute[field: " + fieldName + ", type:" + fieldType + "]"; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/XmlApiClass.as b/src/com/googlecode/flexxb/api/XmlApiClass.as new file mode 100644 index 0000000..4cc3855 --- /dev/null +++ b/src/com/googlecode/flexxb/api/XmlApiClass.as @@ -0,0 +1,276 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.AccessorType; + import com.googlecode.flexxb.annotation.contract.Constants; + + import flash.utils.Dictionary; + + use namespace flexxb_api_internal; + + [XmlClass(alias="XmlClass")] + [ConstructorArg(reference="type")] + [ConstructorArg(reference="alias")] + /** + * API wrapper for a class type. Allows programatically defining all the + * elements that would normally be specified via annotations. + * @author Alexutz + * + */ + public class XmlApiClass extends FxClass + { + /** + * + */ + [XmlAttribute] + /** + * Class alias + * @default + */ + public var alias:String; + /** + * + */ + [XmlAttribute] + /** + * Namespace prefix + * @default + */ + public var prefix:String; + /** + * + */ + [XmlAttribute] + /** + * Namespace uri + * @default + */ + public var uri:String; + /** + * + */ + [XmlAttribute] + /** + * Flag signaling whether the class members are ordered or not in the xml processing stages + * @default + */ + public var ordered:Boolean; + /** + * + */ + [XmlAttribute] + /** + * + * @default + */ + public var useNamespaceFrom:String; + /** + * + */ + [XmlAttribute] + /** + * Name of the field which will be considered as an identifier for the class instance + * @default + */ + public var idField:String; + /** + * + */ + [XmlAttribute] + /** + * Name of the field which is considered to be the default value + * @default + */ + public var defaultValueField:String; + /** + * Class namespace list + */ + flexxb_api_internal var namespaces:Dictionary; + + /** + * Constructor + * @param type class type + * @param alias class alias + */ + public function XmlApiClass(type:Class = null, alias:String = null) + { + super(type); + this.alias = alias; + } + + /** + * Set the default namespace for this class + * @param value + * + */ + public function set defaultNamespace(value:Namespace):void + { + if (value) + { + uri = value.uri; + prefix = value.prefix; + } + } + + /** + * Add a namespace to the class namespace list + * @param ns target namespace + * @return reference to the target namespace + * @throws error if the namespace is already registered in the class' namespace list + * @see FxNamesapce + */ + internal function addNamespace(ns:XmlApiNamespace):XmlApiNamespace + { + if (ns) + { + if (namespaces) + { + var existing:XmlApiNamespace = namespaces[ns.prefix]; + if (existing) + { + if (existing.uri != ns.uri) + { + throw new Error("A namespace already exists with the same prefix but a different uri!\n Existing namespace: " + existing + "\nNamespace to add: " + ns); + } + return existing; + } + } + else + { + namespaces = new Dictionary(); + } + namespaces[ns.prefix] = ns; + } + return ns; + } + + /** + * Remove a namespace from the class namespace list + * @param ns target namespace + * + */ + internal function removeNamespace(ns:XmlApiNamespace):void + { + if (ns && namespaces) + { + for each(var member:XmlApiMember in members) + { + if (member.nameSpace && member.nameSpace.prefix == ns.prefix) + { + return; + } + } + delete namespaces[ns.prefix]; + } + } + + /** + * Add a field mapped to an xml attribute + * @param fieldName name of the target field + * @param fieldType type of the target field + * @param access field access type + * @param alias field alias in the xml mapping + * @return FxAttribute instance + * @see FxAttribute + * @see AccessorType + * + */ + public function addAttribute(fieldName:String, fieldType:Class, access:AccessorType = null, alias:String = null):XmlApiAttribute + { + var attribute:XmlApiAttribute = XmlApiAttribute.create(fieldName, fieldType, access, alias); + addMember(attribute); + return attribute; + } + + /** + * Add a field mapped to an xml element + * @param fieldName name of the target field + * @param fieldType type of the target field + * @param access field access type + * @param alias field alias in the xml mapping + * @return FxElement instance + * @see FxElement + * @see AccessorType + * + */ + public function addElement(fieldName:String, fieldType:Class, access:AccessorType = null, alias:String = null):XmlApiElement + { + var element:XmlApiElement = XmlApiElement.create(fieldName, fieldType, access, alias); + addMember(element); + return element; + } + + /** + * Add an array field mapped to an xml element + * @param fieldName name of the target field + * @param fieldType type of the target field (Array, ArrayCollection, ListCollectionView etc.) + * @param access field access type + * @param alias field alias in the xml mapping + * @return FxArray instance + * @see FxArray + * @see AccessorType + * + */ + public function addArray(fieldName:String, fieldType:Class, access:AccessorType = null, alias:String = null):XmlApiArray + { + var array:XmlApiArray = XmlApiArray.create(fieldName, fieldType, access, alias); + addMember(array); + return array; + } + + public override function getGlobalAnnotations():Array + { + var nsList:Array = []; + for (var nsKey:* in namespaces) + { + nsList.push(namespaces[nsKey]); + } + return nsList; + } + + protected override function onMemberAdded(member:FxMember):void + { + addNamespace(XmlApiMember(member).nameSpace); + } + + public override function getMetadataName():String + { + return XmlClass.ANNOTATION_NAME; + } + + public override function getMappingValues():Dictionary + { + var values:Dictionary = super.getMappingValues(); + values[XmlConstants.ALIAS] = alias; + values[XmlConstants.NAMESPACE_PREFIX] = prefix; + values[XmlConstants.NAMESPACE_URI] = uri; + values[Constants.ORDERED] = ordered; + values[XmlConstants.USE_CHILD_NAMESPACE] = useNamespaceFrom; + values[Constants.ID] = idField; + values[XmlConstants.VALUE] = defaultValueField; + return values; + } + + public override function toString():String + { + return "XmlClass[type: " + type + ", alias:" + alias + "]"; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/XmlApiElement.as b/src/com/googlecode/flexxb/api/XmlApiElement.as new file mode 100644 index 0000000..dc922ce --- /dev/null +++ b/src/com/googlecode/flexxb/api/XmlApiElement.as @@ -0,0 +1,111 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.AccessorType; + + import flash.utils.Dictionary; + + [XmlClass(alias="XmlElement")] + [ConstructorArg(reference="field")] + [ConstructorArg(reference="alias")] + /** + * + * @author Alexutz + * + */ + public class XmlApiElement extends XmlApiMember + { + public static const INCOMING_XML_NAME:String = "XmlElement"; + + /** + * + * @param name + * @param type + * @param accessType + * @param alias + * @return + * + */ + public static function create(name:String, type:Class, accessType:AccessorType = null, alias:String = null):XmlApiElement + { + var field:FxField = new FxField(name, type, accessType); + var element:XmlApiElement = new XmlApiElement(field, alias); + return element; + } + + /** + * + */ + [XmlAttribute] + public var getFromCache:Boolean; + /** + * + */ + [XmlAttribute] + public var serializePartialElement:Boolean; + /** + * + */ + [XmlAttribute] + public var getRuntimeType:Boolean; + + [XmlAttribute] + public var nillable:Boolean; + + [XmlAttribute] + public var wrapCDATA:Boolean; + + /** + * + * @param field + * @param alias + * + */ + public function XmlApiElement(field:FxField = null, alias:String = null) + { + super(field, alias); + } + + public override function getMetadataName():String + { + return XmlElement.ANNOTATION_NAME; + } + + public override function getMappingValues():Dictionary + { + var values:Dictionary = super.getMappingValues(); + values[XmlConstants.GET_FROM_CACHE] = getFromCache; + values[XmlConstants.SERIALIZE_PARTIAL_ELEMENT] = serializePartialElement; + values[XmlConstants.GET_RUNTIME_TYPE] = getRuntimeType; + values[XmlConstants.NILLABLE] = nillable; + values[XmlConstants.WRAP_CDATA] = wrapCDATA; + return values; + } + + /** + * Get string representation of the current instance + * @return string representing the current instance + */ + public function toString():String + { + return "XmlElement[field: " + fieldName + ", type:" + fieldType + "]"; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/XmlApiMember.as b/src/com/googlecode/flexxb/api/XmlApiMember.as new file mode 100644 index 0000000..6b292e0 --- /dev/null +++ b/src/com/googlecode/flexxb/api/XmlApiMember.as @@ -0,0 +1,128 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.Constants; + + import flash.utils.Dictionary; + + use namespace flexxb_api_internal; + + /** + * + * @author Alexutz + * + */ + public class XmlApiMember extends FxMember + { + + [XmlAttribute] + /** + * + * @default + */ + public var alias:String; + + [XmlAttribute] + /** + * + * @default + */ + public var idref:Boolean; + + [XmlAttribute] + /** + * + * @default + */ + public var order:Number; + + [XmlAttribute] + /** + * + */ + public var isRequired:Boolean; + + /** + * @private + */ + protected var _nameSpace:XmlApiNamespace; + + /** + * + * @param field + * @param alias + * + */ + public function XmlApiMember(field:FxField = null, alias:String = null) + { + super(field); + this.alias = alias; + } + + [XmlElement(alias="*")] + /** + * + * @return + */ + public final function get nameSpace():XmlApiNamespace + { + return _nameSpace; + } + + /** + * + * @param value + */ + public final function set nameSpace(value:XmlApiNamespace):void + { + _nameSpace = value; + if (getOwner()) + { + if (value) + { + _nameSpace = XmlApiClass(getOwner()).addNamespace(value); + } + else + { + XmlApiClass(getOwner()).removeNamespace(value); + } + } + } + + /** + * + * @param ns + */ + public function setNamespace(ns:Namespace):void + { + nameSpace = XmlApiNamespace.create(ns); + } + + public override function getMappingValues():Dictionary + { + var values:Dictionary = super.getMappingValues(); + values[XmlConstants.ALIAS] = alias; + if (!isNaN(order)) + values[Constants.ORDER] = order; + values[Constants.IDREF] = idref; + values[Constants.REQUIRED] = isRequired; + return values; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/XmlApiNamespace.as b/src/com/googlecode/flexxb/api/XmlApiNamespace.as new file mode 100644 index 0000000..702e0d5 --- /dev/null +++ b/src/com/googlecode/flexxb/api/XmlApiNamespace.as @@ -0,0 +1,70 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import flash.utils.Dictionary; + + [XmlClass(alias="Namespace")] + [ConstructorArg(reference="prefix")] + [ConstructorArg(reference="uri")] + public final class XmlApiNamespace implements IFxMetaProvider + { + [XmlAttribute] + public var prefix:String; + + [XmlAttribute] + public var uri:String; + + public function XmlApiNamespace(prefix:* = null, uri:* = null) + { + this.prefix = prefix; + this.uri = uri; + } + + public function getMetadataName():String + { + return "Namespace"; + } + + public function getMappingValues():Dictionary + { + var values:Dictionary = new Dictionary(); + values[XmlConstants.NAMESPACE_PREFIX] = prefix; + values[XmlConstants.NAMESPACE_URI] = uri; + return values; + } + + /** + * Get string representation of the current instance + * @return string representing the current instance + */ + public function toString():String + { + return "Namespace[ prefix: " + prefix + ", uri: " + uri + "]"; + } + + public static function create(ns:Namespace):XmlApiNamespace + { + if (ns) + { + return new XmlApiNamespace(ns.prefix, ns.uri); + } + return null; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/flexxb_api_internal.as b/src/com/googlecode/flexxb/api/flexxb_api_internal.as new file mode 100644 index 0000000..776d72f --- /dev/null +++ b/src/com/googlecode/flexxb/api/flexxb_api_internal.as @@ -0,0 +1,23 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + /** + * + */ + public namespace flexxb_api_internal = "http://code.google.com/p/flexxb/api"; +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/schema/FlexXB-XML.xsd b/src/com/googlecode/flexxb/api/schema/FlexXB-XML.xsd new file mode 100644 index 0000000..792f366 --- /dev/null +++ b/src/com/googlecode/flexxb/api/schema/FlexXB-XML.xsd @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the field as being rendered as an + attribute. + + + + + + + + + Defines the field as being rendered as an element. + + + + + + + + + + + + + + + Defines the field as being rendered as a list of + elements. + + + + + + + + + + + + + + + + + + Defines the enclosing xml the is rendered for the + specified type. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/com/googlecode/flexxb/api/schema/FlexXB.xsd b/src/com/googlecode/flexxb/api/schema/FlexXB.xsd new file mode 100644 index 0000000..c57e072 --- /dev/null +++ b/src/com/googlecode/flexxb/api/schema/FlexXB.xsd @@ -0,0 +1,87 @@ + + + + + Specifies the type of access defined by the class + field: readonly(only a getter is defined), writeonly (only a setter + is defined), readwrite (getter and setter are defined or a field) + + + + + + + + + + + Specifies the current stage of processing. Takes + two values: serialize, deserialize. + + + + + + + + + + Defined the class field (field, getter and/or + setter definition). A field is identified by name, type and access + type. + + + + + + + + + A constructor argument is a way to say to the FlexXB engine that + objects of a certain type need a special way to be instantiated in the deserialization + stage. A constructor argument is linked to a class field. Usually, when having + parameterized arguments, in the constructor these values are mapped to specific fields + within the object. + + + + + + + + + + + + + + + + + + Defines the class. + + + + + + + + + + + + + + + + This is the root element + + + + \ No newline at end of file diff --git a/src/com/googlecode/flexxb/cache/ICacheProvider.as b/src/com/googlecode/flexxb/cache/ICacheProvider.as new file mode 100644 index 0000000..21e0646 --- /dev/null +++ b/src/com/googlecode/flexxb/cache/ICacheProvider.as @@ -0,0 +1,68 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.cache +{ + /** + * This interface defines a cache provider recognised by FlexXB engine. + * @author Alexutzutz + * + */ + public interface ICacheProvider + { + /** + * Determines whether an object with the given id is aleady cached. + * @param id the id under which the object should have been cached + * @param clasz the class of the object + * @return true if there is an object cached under the given id and class. + * + */ + function isInCache(id:String, clasz:Class):Boolean; + + /** + * Get an instance of the specified type and with the specified id + * from the cache + * @param id object identifier + * @param clasz object class + * @return instance defined by id and type if it exists, null otherwise + * + */ + function getFromCache(id:String, clasz:Class):*; + + + function put(id:String, itemm:*, clasz:Class):void; + + /** + * Gets a new instance of the specified object class. The constructor may + * require arguments which are supplied with the parameters list.
+ * After the instance is created it will be placed into the cache. + * @param clasz object class + * @param id object identifier + * @param parameters parameter list to be used when calling the constructor + * @return newly created instance + * + */ + function getNewInstance(clasz:Class, id:String, parameters:Array = null):*; + + /** + * Clears the cache for all the objects with given class. + * If no class is specified, then all cache is cleared. + * @param typeList List of types for which the cache will be flushed. ALL instances will be flushed if null or empty + */ + function clearCache(...typeList):void; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/cache/IPooledObject.as b/src/com/googlecode/flexxb/cache/IPooledObject.as new file mode 100644 index 0000000..7c5e060 --- /dev/null +++ b/src/com/googlecode/flexxb/cache/IPooledObject.as @@ -0,0 +1,42 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.cache +{ + /** + * This is the interface for objects used by the object cache. Using this interface will give + * the implementor objects the ability to get their cleanup method called when they are returned + * to the cache. The object Cache can store any type of objects, regardless whether they implement + * IPooledObject or not. + * @author aCiobanu + * + */ + public interface IPooledObject + { + /** + * Easy access to the object type + * @return + * + */ + function get type():Object; + + /** + * Called when the object is released from UI use and back into the object cache + */ + function clear():void; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/cache/ObjectCache.as b/src/com/googlecode/flexxb/cache/ObjectCache.as new file mode 100644 index 0000000..e12a599 --- /dev/null +++ b/src/com/googlecode/flexxb/cache/ObjectCache.as @@ -0,0 +1,158 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.cache +{ + import avmplus.Types; + import flash.system.ApplicationDomain; + import flash.utils.Dictionary; + + + public class ObjectCache implements ICacheProvider + { + private var cacheMap:Dictionary = new Dictionary(); + + public function ObjectCache() + { + cacheMap = new Dictionary(); + } + + public function isInCache(id:String, clasz:Class):Boolean + { + return cacheMap[clasz] && cacheMap[clasz][id] != null; + } + + public function getFromCache(id:String, clasz:Class):* + { + if (cacheMap[clasz]) + { + return cacheMap[clasz][id]; + } + else + { + return null; + } + } + + public function getNewInstance(clasz:Class, id:String, parameters:Array = null):* + { + if (clasz) + { + var item:Object = parameters ? getInstance(clasz, parameters) : new clasz(); + + if (id != null) + { + var map:Dictionary = cacheMap[clasz]; + if (map == null) + { + map = new Dictionary(); + cacheMap[clasz] = map; + } + map[id] = item; + } + } + return item; + } + + /** + * Put an object in the cache + * @param id the id under which the object will be cached + * @param item the object itself + * @return if the object was succesfuly cached. + * + */ + public function putObject(id:String, item:Object):void + { + if (id && item) + { + var qualifiedName:String = Types.getQualifiedClassName(item); + var clasz:Class = ApplicationDomain.currentDomain.getDefinition(qualifiedName) as Class; + if (!cacheMap[clasz]) + { + cacheMap[clasz] = new Dictionary(); + } + cacheMap[clasz][id] = item; + } + } + + public function put(id:String, item:*, clasz:Class):void + { + if (!cacheMap[clasz]) + { + cacheMap[clasz] = new Dictionary(); + } + cacheMap[clasz][id] = item; + } + + public function clearCache(...typeList):void + { + if (typeList && typeList.length > 0) + { + for each(var type:Object in typeList) + { + if (cacheMap[type]) + { + delete cacheMap[type]; + } + } + } + else + { + for (var key:* in cacheMap) + { + delete cacheMap[key]; + } + cacheMap = new Dictionary(); + } + } + + private function getInstance(clasz:Class, args:Array = null):* + { + if (!args) + { + args = []; + } + switch (args.length) + { + case 0: + return new clasz(); + case 1: + return new clasz(args[0]); + case 2: + return new clasz(args[0], args[1]); + case 3: + return new clasz(args[0], args[1], args[2]); + case 4: + return new clasz(args[0], args[1], args[2], args[3]); + case 5: + return new clasz(args[0], args[1], args[2], args[3], args[4]); + case 6: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + case 8: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + case 9: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); + case 10: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/cache/ObjectPool.as b/src/com/googlecode/flexxb/cache/ObjectPool.as new file mode 100644 index 0000000..2751802 --- /dev/null +++ b/src/com/googlecode/flexxb/cache/ObjectPool.as @@ -0,0 +1,185 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.cache +{ + import com.googlecode.flexxb.util.Instanciator; + import avmplus.Types; + import flash.utils.Dictionary; + + /** + * This is the cache for object instances. It maintains a pool for each + * object type. It works a bit differently... objects in pool are used + * then released to be used by others. While an object is in use it cannot + * be reasigned to other. Once the user is done with the instance, it must + * call releaseInstance method. + *

ObjectPool does not use an id. Objects are assigned baed on the used + * state. If all available objects are in use then a new instance will be + * created. If there is an object released, it will be passed on for use. + * That's why sometimes it is required to clean the objects after use. This + * is where the IPooledObject interface comes to use by exposing the clear + * method which should be implemented by the objects that require some + * cleanup before being reused. + * @author aCiobanu + * + */ + public final class ObjectPool implements ICacheProvider + { + private static const _instance:ObjectPool = new ObjectPool(); + /** + * Easy access instance + * @return + * + */ + public static function get instance():ObjectPool + { + return _instance; + } + + private var cacheMap:Dictionary; + + public function ObjectPool() + { + cacheMap = new Dictionary(); + } + + public function isInCache(id:String, type:Class):Boolean + { + var store:TypeCache = cacheMap[type] as TypeCache; + return store && store.hasItemsAvailable(); + } + + public function getFromCache(id:String, type:Class):* + { + if (!type) + { + throw new Error("Invalid type"); + } + var store:TypeCache = cacheMap[type] as TypeCache; + if (store) + { + return store.getInstance(); + } + return null; + } + + public function getNewInstance(clasz:Class, id:String, parameters:Array = null):* + { + var item:Object; + if (clasz) + { + item = Instanciator.getInstance(clasz, parameters); + putObject(id, clasz, item); + } + return item; + } + + /** + * Mark the view instance as unused + * @param instanceList + * + */ + public function releaseInstance(instance:Object):void + { + if (!instance) return; + var type:Object; + if (instance is IPooledObject) + { + IPooledObject(instance).clear(); + type = IPooledObject(instance).type; + } + else + { + type = Types.getDefinitionByName(Types.getQualifiedClassName(instance)); + } + var store:TypeCache = cacheMap[type] as TypeCache; + if (store) + { + store.releaseInstance(instance); + } + } + + /** + * Tell the cache the display of the attributes started so it will + * at the starting position in the object cache and return object + * instances until it runs out. After that new instances will be + * created and added in the cache + * @param args list of types + * + */ + public function beginNewSequence(...args):void + { + var store:TypeCache; + if (args && args.length > 0) + { + for each(var type:Object in args) + { + store = cacheMap[type] as TypeCache; + if (store) + { + store.resetIndex(); + } + } + } + else + { + for each(store in cacheMap) + { + store.resetIndex(); + } + } + } + + public function clearCache(...typeList):void + { + if (typeList && typeList.length > 0) + { + for each(var type:Object in typeList) + { + if (cacheMap[type]) + { + delete cacheMap[type]; + } + } + } + else + { + for (var key:* in cacheMap) + { + delete cacheMap[key]; + } + } + } + + private function putObject(id:String, clasz:Class, object:Object):void + { + var store:TypeCache = cacheMap[clasz] as TypeCache; + if (!store) + { + store = new TypeCache(clasz); + cacheMap[clasz] = store; + } + store.putObject(id, object); + } + + + public function put(id:String, itemm:*, clasz:Class):void + { + throw new Error("not implemented"); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/cache/TypeCache.as b/src/com/googlecode/flexxb/cache/TypeCache.as new file mode 100644 index 0000000..508a00a --- /dev/null +++ b/src/com/googlecode/flexxb/cache/TypeCache.as @@ -0,0 +1,147 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.cache +{ + /** + * This is the actual store for the object instances. + * @author aCiobanu + * @private + */ + internal final class TypeCache + { + /** + * Type of objects being stored + */ + public var type:Class; + /** + * @private + */ + private var objectStore:Array = []; + /** + * @private + */ + private var objectUsage:Array = []; + /** + * @private + */ + private var currentIndex:int = 0; + + /** + * Constructor + * @param type the object type + * + */ + public function TypeCache(type:Class) + { + this.type = type; + } + + /** + * Get an object instance stored in cache that is not marked as used. + * Returns null if such an instance is not found. + * @return + * + */ + public function getInstance():Object + { + var object:Object; + if (objectStore && currentIndex < objectStore.length) + { + objectUsage[currentIndex] = true; + object = objectStore[currentIndex]; + while (objectUsage[++currentIndex]) + { + } + } + return object; + } + + /** + * Mark the instance as unused so other clients may take hold of it and use it in dsplay + * @param instance + * + */ + public function releaseInstance(instance:Object):void + { + if (!instance) return; + var index:int = objectStore.indexOf(instance, currentIndex); + if (index == -1) + { + index = objectStore.indexOf(instance); + } + if (index > -1) + { + objectUsage[index] = false; + if (currentIndex > index) + { + currentIndex = index; + } + } + } + + /** + * Signal the store that the cache index should be resetted + * thus instances would come from it again and only created if + * all stored ones get used up + * + */ + public function resetIndex():void + { + currentIndex = 0; + var loop:int = 0; + while (loop < objectUsage.length) + { + objectUsage[loop++] = false; + } + } + + /** + * + * @return + * + */ + public function hasItemsAvailable():Boolean + { + return objectStore && currentIndex < objectStore.length; + } + + /** + * Clear the cache + * + */ + public function clear():void + { + currentIndex = 0; + objectStore = []; + objectUsage = []; + } + + /** + * @private + * @param id + * @param object + * + */ + internal function putObject(id:String, object:Object):void + { + objectStore.push(object) + objectUsage.push(true); + currentIndex++; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/converter/ClassTypeConverter.as b/src/com/googlecode/flexxb/converter/ClassTypeConverter.as new file mode 100644 index 0000000..d1b9a50 --- /dev/null +++ b/src/com/googlecode/flexxb/converter/ClassTypeConverter.as @@ -0,0 +1,43 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.converter +{ + import avmplus.Types; + + /** + * Converter for Class objects + * @author Alexutz + * + */ + public final class ClassTypeConverter implements IConverter + { + public function get type():Class + { + return Class; + } + + public function toString(object:Object):String + { + return object ? Types.getQualifiedClassName(object) : ""; + } + + public function fromString(value:String):Object + { + return value ? Types.getDefinitionByName(value) : null; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/converter/IConverter.as b/src/com/googlecode/flexxb/converter/IConverter.as new file mode 100644 index 0000000..2c8b134 --- /dev/null +++ b/src/com/googlecode/flexxb/converter/IConverter.as @@ -0,0 +1,51 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.converter +{ + + /** + * Interface defining how strings can be converted to + * specific objects and viceversa. + * @author aCiobanu + * + */ + public interface IConverter + { + /** + * + * @return Object type + * + */ + function get type():Class; + + /** + * Get the string representation of the specified object + * @param item Target object + * @return String representation of the specified object + * + */ + function toString(item:Object):String; + + /** + * Get the object whose representation is the specified value + * @param value String parameter from which the object is created + * @return Object whose representation is the specified value + * + */ + function fromString(value:String):Object; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/converter/W3CDateConverter.as b/src/com/googlecode/flexxb/converter/W3CDateConverter.as new file mode 100644 index 0000000..21e1385 --- /dev/null +++ b/src/com/googlecode/flexxb/converter/W3CDateConverter.as @@ -0,0 +1,186 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.converter +{ + /** + * Date converter conforming to the W3C standard + * @author Alexutz + * + */ + public final class W3CDateConverter implements IConverter + { + /** + * + * @see IConverter#type() + * + */ + public function get type():Class + { + return Date; + } + + /** + * Returns a date string formatted according to W3CDTF. + * @param d + * @param includeMilliseconds Determines whether to include the + * milliseconds value (if any) in the formatted string. + * + * @returns date string + */ + public function toString(obj:Object):String + { + var d:Date = obj as Date; + var date:Number = d.getUTCDate(); + var month:Number = d.getUTCMonth(); + var hours:Number = d.getUTCHours(); + var minutes:Number = d.getUTCMinutes(); + var seconds:Number = d.getUTCSeconds(); + var milliseconds:Number = d.getUTCMilliseconds(); + var timeOffset:Number = d.getTimezoneOffset(); + var sb:String = new String(); + + sb += d.getUTCFullYear() + "-"; + + sb += addLeadingZero(month + 1) + "-"; + + sb += addLeadingZero(date); + + sb += "T"; + + sb += addLeadingZero(hours) + ":"; + + sb += addLeadingZero(minutes) + ":"; + + sb += addLeadingZero(seconds); + + if (milliseconds >= 0) + { + sb += "."; + sb += addLeadingZero(milliseconds, 3); + } + + if (timeOffset < 0) + { + sb += "+"; + timeOffset = -timeOffset; + } + else + { + sb += "-"; + } + var offsetHour:int = timeOffset / 60; + + sb += addLeadingZero(offsetHour) + ":"; + + var offsetMinute:int = timeOffset % 60; + + sb += addLeadingZero(offsetMinute); + + return sb; + } + + private static function addLeadingZero(value:int, count:int = 2):String + { + var val:String = value + ""; + while (val.length < count) + { + val = "0" + val; + } + return val; + } + + /** + * Parses dates that conform to the W3C Date-time Format into Date objects. + * @param str + * @returns date object + * + */ + public function fromString(str:String):Object + { + var finalDate:Date; + if (str) + { + try + { + var dateStr:String = str.substring(0, str.indexOf("T")); + var timeStr:String = str.substring(str.indexOf("T") + 1, str.length); + var dateArr:Array = dateStr.split("-"); + var year:Number = Number(dateArr.shift()); + var month:Number = Number(dateArr.shift()); + var date:Number = Number(dateArr.shift()); + + var multiplier:Number; + var offsetHours:Number; + var offsetMinutes:Number; + var offsetStr:String; + + if (timeStr.indexOf("Z") != -1) + { + multiplier = 1; + offsetHours = 0; + offsetMinutes = 0; + timeStr = timeStr.replace("Z", ""); + } + else if (timeStr.indexOf("+") != -1) + { + multiplier = 1; + offsetStr = timeStr.substring(timeStr.indexOf("+") + 1, timeStr.length); + offsetHours = Number(offsetStr.substring(0, offsetStr.indexOf(":"))); + offsetMinutes = Number(offsetStr.substring(offsetStr.indexOf(":") + 1, offsetStr.length)); + timeStr = timeStr.substring(0, timeStr.indexOf("+")); + } + else if(timeStr.indexOf("-") != -1) // offset is - + { + multiplier = -1; + offsetStr = timeStr.substring(timeStr.indexOf("-") + 1, timeStr.length); + offsetHours = Number(offsetStr.substring(0, offsetStr.indexOf(":"))); + offsetMinutes = Number(offsetStr.substring(offsetStr.indexOf(":") + 1, offsetStr.length)); + timeStr = timeStr.substring(0, timeStr.indexOf("-")); + } + else //date str without offset + { + multiplier = 1; + offsetHours = 0; + offsetMinutes = 0; + } + + var timeArr:Array = timeStr.split(":"); + var hour:Number = Number(timeArr.shift()); + var minutes:Number = Number(timeArr.shift()); + var secondsArr:Array = (timeArr.length > 0) ? String(timeArr.shift()).split(".") : null; + var seconds:Number = (secondsArr != null && secondsArr.length > 0) ? Number(secondsArr.shift()) : 0; + var milliseconds:Number = (secondsArr != null && secondsArr.length > 0) ? Number(secondsArr.shift()) : 0; + var utc:Number = Date.UTC(year, month - 1, date, hour, minutes, seconds, milliseconds); + var offset:Number = (((offsetHours * 3600000) + (offsetMinutes * 60000)) * multiplier); + finalDate = new Date(utc); + //utc-offset? + if (finalDate.toString() == "Invalid Date") + { + throw new Error("This date does not conform to W3CDTF."); + } + } catch (e:Error) + { + var eStr:String = "Unable to parse the string [" + str + "] into a date. "; + eStr += "The internal error was: " + e.toString(); + throw new Error(eStr); + } + } + return finalDate; + } + + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/converter/XmlConverter.as b/src/com/googlecode/flexxb/converter/XmlConverter.as new file mode 100644 index 0000000..238931c --- /dev/null +++ b/src/com/googlecode/flexxb/converter/XmlConverter.as @@ -0,0 +1,41 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.converter +{ + /** + * Converter for XML objects + * @author Alexutz + * + */ + public final class XmlConverter implements IConverter + { + public function get type():Class + { + return XML; + } + + public function toString(object:Object):String + { + return (object as XML).toString(); + } + + public function fromString(value:String):Object + { + return new XML(value); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/Configuration.as b/src/com/googlecode/flexxb/core/Configuration.as new file mode 100644 index 0000000..4421a33 --- /dev/null +++ b/src/com/googlecode/flexxb/core/Configuration.as @@ -0,0 +1,126 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import com.googlecode.flexxb.cache.ICacheProvider; + + /** + * This class defines the settings the FlexXB Core and serialization contexts accept in + * order to control processing. You may override this class to add more settings that + * will be used in your serialization contexts and serializers. + * @author Alexutz + * + */ + public class Configuration + { + /** + * Constructor + * + */ + public function Configuration() + { + } + /** + * Serializing persistable objects can be done by including only the fields + * whose values have been changed. + */ + public var onlySerializeChangedValueFields:Boolean = false; + + /** + * Set this flag to true if you want the engine to ignore missing content. By default this field is set on false. + * By default FlexXB considers a missing serialized content representing a field value as being null and sets null as a value + * for the appropriate field in the ActionScript object. This is particularly usefull when you need to perform subsequent + * calls in order to get pieces of data that will in the end construct the final object. By default, after each call, the + * missing fields in the serialized data will be set to null and such the object will only have the values specified in the last call. + * Set this flag to true in order to ignore missing values and not set null into the appropiate fields. + */ + public var ignoreMissingContent:Boolean = false; + + /** + * Determine the type of the object the response will be deserialised into + * by the namespace defined in the received xml. + * @default true + */ + public var getResponseTypeByNamespace:Boolean = true; + /** + * Determine the type of the object the response will be deserialised into + * by the root element name of the received xml. + * @default true + */ + public var getResponseTypeByTagName:Boolean = true; + /** + * Determine the type of the object the response will be deserialised into + * by the xsi:type attribute present in the xml element representing the object. + * @default false + */ + public var getResponseTypeByXsiType:Boolean = false; + /** + * Set this flag to true if you want special chars to be escaped in the xml. + * If set to false, text containing special characters will be enveloped in a CDATA tag. + * This option applies to xml elements. For xml attributes special chars are automatically + * escaped. + */ + public var escapeSpecialChars:Boolean = false; + + /** + * Flag signaling the presence or not of a cache provider. It is a + * quick determination of the use of a caching mechanism. + * @return true if cache is used, false otherwise + * + */ + public var allowCaching:Boolean; + + /** + * Flag signaling whether the engine should attempt to automatically + * determine the version of the received serialized document. This setting + * is overridden by specifying a non empty version value when + * deserializing the serialized document. + * @return true if detection is auto, false otherwise + * + */ + public var autoDetectVersion:Boolean; + + /** + * Reference to an ICacheProvider implementor. Use this field to instruct the engine to use + * an object caching mechanism. + */ + public var cacheProvider:ICacheProvider; + /** + * Reference to a version extractor instance used to determine automatically the version of + * an serialized document. + */ + private var _versionExtractor:IVersionExtractor; + + + public function setCacheProvider(value:ICacheProvider):void + { + cacheProvider = value; + allowCaching = value != null; + } + + public function get versionExtractor():IVersionExtractor + { + return _versionExtractor; + } + + public function set versionExtractor(value:IVersionExtractor):void + { + _versionExtractor = value; + autoDetectVersion = value != null; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/DescriptorStore.as b/src/com/googlecode/flexxb/core/DescriptorStore.as new file mode 100644 index 0000000..820264a --- /dev/null +++ b/src/com/googlecode/flexxb/core/DescriptorStore.as @@ -0,0 +1,249 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import avmplus.R; + + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.parser.MetaParser; + import com.googlecode.flexxb.interfaces.ISerializable; + import avmplus.Types; + + import flash.utils.Dictionary; + + /** + * + * @author aCiobanu + * + */ + public final class DescriptorStore + { + /** + * @private + */ + private var descriptorCache:Dictionary = new Dictionary(); + /** + * @private + */ + private var parser:MetaParser; + + private var _factory:AnnotationFactory; + + public function DescriptorStore(theFactory:AnnotationFactory) + { + parser = new MetaParser(theFactory); + _factory = theFactory; + } + + public function get factory():AnnotationFactory + { + return _factory; + } + + public function getDescriptor(item:*, version:String = ""):XmlClass + { + var className:String = Types.getQualifiedClassName(item); + + var store:ResultStore = descriptorCache[className]; + + if (store == null) + { + store = put(item, className); + } + + return store.getDescriptor(version); + } + + public function getClassReferenceByCriteria(field:String, value:String, version:String = ""):Class + { + var descriptor:Object; + for each (var store:ResultStore in descriptorCache) + { + descriptor = store.getDescriptor(version); + if (descriptor && descriptor.hasOwnProperty(field) && descriptor[field] == value) + { + return XmlClass(descriptor).type; + } + } + return null; + } + + /** + * Determine whether the object is custom serializable or not + * @param object + * @return true if the object is custom serialisable, false otherwise + * + */ + public function isCustomSerializable(item:Object):Boolean + { + var className:String = Types.getQualifiedClassName(item); + + var store:ResultStore = descriptorCache[className]; + if (store == null) + { + store = put(item, className); + } + + return store.reference != null; + } + + /** + * Get the reference instance defined for a custom serializable type + * @param clasz + * @return object type instance + * + */ + public function getCustomSerializableReference(clasz:Class):ISerializable + { + var className:String = Types.getQualifiedClassName(clasz); + return getDefinition(clasz, className).reference as ISerializable; + } + + /** + * + * @param xmlDescriptor + * @param type + * + */ + public function registerDescriptor(xmlDescriptor:Object, type:Class):void + { + var className:String = Types.getQualifiedClassName(type); + if (hasDescriptorDefined(className)) + { + return; + } + putDescriptorInCache(xmlDescriptor, className, false); + } + + private function describe(json:Object):Array + { + //get class annotation + var descriptors:Array = parser.parseDescriptor(json); + return descriptors; + } + + private function hasDescriptorDefined(className:String):Boolean + { + return descriptorCache[className] != null; + } + + private function getDefinition(object:Object, className:String):ResultStore + { + if (descriptorCache[className] == null) + { + put(object, className); + } + return descriptorCache[className]; + } + + private function put(object:*, className:String):ResultStore + { + var json:Object = R.describe(object, R.ACCESSORS | R.VARIABLES | R.METADATA | R.TRAITS | R.INTERFACES | R.CONSTRUCTOR); + + var customSerializable:Boolean; + for each (var interf:String in json.traits.interfaces) + { + if (interf == "com.googlecode.flexxb.interfaces::ISerializable") + { + customSerializable = true; + break; + } + } + return putDescriptorInCache(json, className, customSerializable); + } + + private function putDescriptorInCache(descriptor:Object, className:String, customSerializable:Boolean):ResultStore + { + var xmlClasses:Array; + var referenceObject:Object; + if (customSerializable) + { + var cls:Class = Types.getDefinitionByName(className) as Class; + referenceObject = new cls(); + } + else + { + xmlClasses = describe(descriptor); + } + var resultStore:ResultStore = new ResultStore(xmlClasses, customSerializable, referenceObject); + descriptorCache[className] = resultStore; + return resultStore; + } + } +} + +import com.googlecode.flexxb.annotation.contract.XmlClass; +import com.googlecode.flexxb.annotation.contract.Constants; + +import flash.utils.Dictionary; + +/** + * + * @author Alexutz + * @private + */ +internal class ResultStore +{ + /** + * @private + */ + private var descriptors:Dictionary; + /** + * @private + */ + public var customSerializable:Boolean; + /** + * @private + */ + public var reference:Object; + + /** + * @private + * @param descriptor + * @param customSerializable + * @param reference + * + */ + public function ResultStore(descriptors:Array, customSerializable:Boolean, reference:Object) + { + this.customSerializable = customSerializable; + this.reference = reference; + this.descriptors = new Dictionary(); + for each(var descriptor:XmlClass in descriptors) + { + this.descriptors[(descriptor.version ? descriptor.version : Constants.DEFAULT)] = descriptor; + } + } + + /** + * Get the descriptor associated to the version supplied. If none is found + * the default descriptor will be returned + * @param version version value + * @return IClassAnnotation implementor instance + * + */ + public function getDescriptor(version:String):XmlClass + { + var annotationVersion:String = version; + if (!descriptors[annotationVersion]) + { + annotationVersion = Constants.DEFAULT; + } + return descriptors[annotationVersion]; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/ElementStack.as b/src/com/googlecode/flexxb/core/ElementStack.as new file mode 100644 index 0000000..f682d3c --- /dev/null +++ b/src/com/googlecode/flexxb/core/ElementStack.as @@ -0,0 +1,91 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.core +{ + internal final class ElementStack + { + private var stack:Array = []; + + private var index:int = -1; + + public function ElementStack() + { + } + + public function beginDocument():void + { + + } + + /** + * Returns a reference to the current object being processed + * @return + * + */ + public function getCurrent():Object + { + if (stack.length > 0) + { + return stack[stack.length - 1]; + } + return null; + } + + /** + * Returns a reference to the current object's parent. + * @return + * + */ + public function getParent():Object + { + if (index > 0) + { + return stack[index - 1]; + } + return null; + } + + + public function push(item:Object):Boolean + { + if (stack.indexOf(item) == -1) + { + stack[++index] = item; + return true; + } + return false; + } + + public function pushNoCheck(item:Object):void + { + stack[++index] = item; + } + + public function pop():Object + { + index--; + return stack.pop(); + } + + public function endDocument():void + { + stack.length = 0; + index = -1; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/FlexXBApi.as b/src/com/googlecode/flexxb/core/FlexXBApi.as new file mode 100644 index 0000000..1cc7203 --- /dev/null +++ b/src/com/googlecode/flexxb/core/FlexXBApi.as @@ -0,0 +1,143 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import avmplus.RMember; + import avmplus.RMeta; + import avmplus.RValue; + import avmplus.RObject; + import com.googlecode.flexxb.api.AccessorTypeConverter; + import com.googlecode.flexxb.api.FxApiWrapper; + import com.googlecode.flexxb.api.FxClass; + import com.googlecode.flexxb.api.FxConstructorArgument; + import com.googlecode.flexxb.api.FxMember; + import com.googlecode.flexxb.api.IFlexXBApi; + import com.googlecode.flexxb.api.IFxMetaProvider; + import com.googlecode.flexxb.api.StageXmlConverter; + import avmplus.Types; + + import flash.utils.Dictionary; + + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * + * @author Alexutz + * @private + */ + internal final class FlexXBApi implements IFlexXBApi + { + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.core.FlexXBApi"); + + private var core:FlexXBCore; + private var store:DescriptorStore; + + /** + * Constructor + * @param core the xml serialization core + * @param store + * + */ + public function FlexXBApi(core:FlexXBCore) + { + this.core = core; + this.store = core.store; + core.context.registerSimpleTypeConverter(new StageXmlConverter()); + core.context.registerSimpleTypeConverter(new AccessorTypeConverter()); + core.processTypes(FxConstructorArgument); + } + + public function processTypeDescriptor(apiDescriptor:FxClass):void + { + if (apiDescriptor) + { + var type:Class = apiDescriptor.type; + store.registerDescriptor(buildTypeDescriptor(apiDescriptor), type); + } + } + + public function processDescriptorsFromXml(xml:XML):void + { + if (xml) + { + var apiWrapper:FxApiWrapper = core.deserialize(xml, FxApiWrapper); + if (apiWrapper) + { + for each (var classDescriptor:FxClass in apiWrapper.descriptors) + { + if (classDescriptor) + { + if (Log.isDebug()) + { + LOG.debug("Processing class {0}", classDescriptor.type); + } + processTypeDescriptor(classDescriptor); + } + } + } + } + } + + public function buildTypeDescriptor(apiClass:FxClass):RObject + { + var xml:RObject = new RObject(); + xml.name = Types.getQualifiedClassName(apiClass.type); + if (apiClass.constructorArguments) + { + for (var i:int = apiClass.constructorArguments.length - 1; i >= 0; i--) + { + var fxConstructorArgument:FxConstructorArgument = apiClass.constructorArguments[i] as FxConstructorArgument; + xml.traits.metadata.push(buildMetadataDescriptor(fxConstructorArgument)); + } + } + var globals:Array = apiClass.getGlobalAnnotations(); + for each(var global:IFxMetaProvider in globals) + { + xml.traits.metadata.push(buildMetadataDescriptor(global)); + } + xml.traits.metadata.push(buildMetadataDescriptor(apiClass)); + for each (var member:FxMember in apiClass.members) + { + var m:RMember = buildFieldDescriptor(member); + xml.traits.variables.push(m); + } + return xml; + } + + public function buildFieldDescriptor(member:FxMember):RMember + { + var xml:RMember = new RMember(member.field.name, Types.getQualifiedClassName(member.field.type), member.field.accessType.toString(), null, null); + xml.metadata.push(buildMetadataDescriptor(member)); + return xml; + } + + private function buildMetadataDescriptor(meta:IFxMetaProvider):RMeta + { + var xml:RMeta = new RMeta(meta.getMetadataName()); + var values:Dictionary = meta.getMappingValues(); + for (var key:* in values) + { + if (values[key] != null) + { + xml.value.push(new RValue(key, values[key])); + } + } + return xml; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/FlexXBCore.as b/src/com/googlecode/flexxb/core/FlexXBCore.as new file mode 100644 index 0000000..cfc93c5 --- /dev/null +++ b/src/com/googlecode/flexxb/core/FlexXBCore.as @@ -0,0 +1,120 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * @private + * @author Alexutz + * + */ + internal final class FlexXBCore implements IFlexXB + { + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.core.FlexXBCore"); + + private var core:SerializationCore; + + private var _context:XmlDescriptionContext; + + private var _configuration:Configuration; + private var _descriptorStore:DescriptorStore; + private var _factory:AnnotationFactory; + + public function FlexXBCore(context:XmlDescriptionContext) + { + this._context = context; + _factory = new AnnotationFactory(); + _descriptorStore = new DescriptorStore(_factory); + _configuration = context.configuration; + core = new SerializationCore(context, _descriptorStore); + _context.initializeContext(_descriptorStore, core); + } + + public function get context():XmlDescriptionContext + { + return _context; + } + + public function get configuration():Configuration + { + return _configuration; + } + + public function processTypes(...args):void + { + if (args && args.length > 0) + { + for each (var item:Object in args) + { + if (item is Class) + { + _descriptorStore.getDescriptor(item); + } + else + { + LOG.error("Excluded from processing because it is not a class: {0}", item); + } + } + } + } + + public function addEventListener(type:String, listener:Function, priority:int = 0, useWeakReference:Boolean = false):void + { + core.addEventListener(type, listener, false, priority, useWeakReference); + } + + public function removeEventListener(type:String, listener:Function):void + { + core.removeEventListener(type, listener, false); + } + + public function serialize(object:*, partial:Boolean = false, version:String = ""):XML + { + core.beginSerialize(); + var data:XML = core.serialize(object, partial, version); + core.endSerialize(); + return data; + } + + public function deserialize(source:XML, objectClass:Class = null, getFromCache:Boolean = false, version:String = ""):* + { + core.beginDeserialise(); + //determine the source document version + if (!version && configuration.autoDetectVersion) + { + version = configuration.versionExtractor.getVersion(source); + } + var object:Object = core.deserialize(source, objectClass, getFromCache, version); + core.endDeserialise(); + return object; + } + + + public function get factory():AnnotationFactory + { + return _factory; + } + + public function get store():DescriptorStore + { + return _descriptorStore; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/FxBEngine.as b/src/com/googlecode/flexxb/core/FxBEngine.as new file mode 100644 index 0000000..9a4f5ad --- /dev/null +++ b/src/com/googlecode/flexxb/core/FxBEngine.as @@ -0,0 +1,128 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import com.googlecode.flexxb.api.IFlexXBApi; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * Entry point for AS3-? (de)serialization. Allows new annotation registration. + * The main access point consist of two methods: serialize() and deserialize, each corresponding to the specific stage in the conversion process. + * By default it registeres the built-in xml handling annotations through the xml description context. + * + * @author aCiobanu + * + */ + public final class FxBEngine + { + private static var _instance:FxBEngine; + + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.core.FxBEngine"); + + private var _api:IFlexXBApi; + + private var contextMap:Object; + + /** + * Not a singleton, but an easy access instance. + * @return instance of FlexXBEngine + * + */ + public static function get instance():FxBEngine + { + if (!_instance) + { + _instance = new FxBEngine(); + } + return _instance; + } + + /** + * Constructor + * + */ + public function FxBEngine() + { + contextMap = {}; + registerDescriptionContext("XML", new XmlDescriptionContext()); + } + + /** + * Get a reference to the api object + * @return instance of type com.googlecode.flexxb.api.IFlexXBApi + * + */ + public function get api():IFlexXBApi + { + if (!_api) + { + _api = new FlexXBApi(getXmlSerializer() as FlexXBCore); + } + return _api; + } + + /** + * + * @param name + * @param context + * + */ + public function registerDescriptionContext(name:String, context:XmlDescriptionContext):void + { + if (!name || !context) + { + throw new Error(); + } + if (contextMap[name]) + { + throw new Error(); + } + contextMap[name] = {context: context, core: null}; + } + + /** + * + * @param name + * @return + * + */ + public function getSerializer(name:String):IFlexXB + { + var item:Object = contextMap[name]; + if (item) + { + if (!item.core) + { + item.core = new FlexXBCore(item.context); + } + return item.core as IFlexXB; + } + return null; + } + + /** + * + * @return + * + */ + public function getXmlSerializer():IFlexXB + { + return getSerializer("XML"); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/IFlexXB.as b/src/com/googlecode/flexxb/core/IFlexXB.as new file mode 100644 index 0000000..53388b1 --- /dev/null +++ b/src/com/googlecode/flexxb/core/IFlexXB.as @@ -0,0 +1,96 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + + /** + * This interface defines a core that handles a specific way of serializing/deserializing + * and object. It makes use of a serialization context to inject all the particularities + * of a specific serialization format. Also, within the context serializers and converters + * are registered. + * @author Alexutz + * + */ + public interface IFlexXB + { + /** + * Get a reference to the context initiating this serializer + * @return Description context instance + * + */ + function get context():XmlDescriptionContext; + + /** + * Get a reference to the configuration object + * @return instance of type com.googlecode.flexxb.Configuration + * + */ + function get configuration():Configuration; + + /** + * Do an early processing of types involved in the communication process if one + * wants to bypass the lazy processing method implemented by the serializer. + * @param args types to be processed + * + */ + function processTypes(...args):void; + + /** + * Add a listener to an event being raised by the serialization process to signal various stages. + *
There are four stages being signaled through events: preserialize, postserialize, predeserialize + * and postdeserialize. + * @param type event type + * @param listener listener function + * @param priority priority + * @param useWeakReference + * + */ + function addEventListener(type:String, listener:Function, priority:int = 0, useWeakReference:Boolean = false):void; + + /** + * Remove a registered listener for a stage event + * @param type event type + * @param listener listener function + * + */ + function removeEventListener(type:String, listener:Function):void; + + /** + * Convert an object to a serialized representation(string - XML - or byte array). + * @param object object to be converted. + * @param partial serialize the object in partial mode (only the object's id field) + * @param version + * @return serialized representation of the given object + * + */ + function serialize(object:*, partial:Boolean = false, version:String = ""):XML; + + /** + * Convert a serialized data (string or byte) to an AS3 object counterpart + * @param source serialized content to be deserialized + * @param objectClass object class + * @param getFromCache get the object from the model object cache if it exists, without processing the serialized data + * @param version + * @return object of type objectClass + * + */ + function deserialize(source:XML, objectClass:Class = null, getFromCache:Boolean = false, version:String = ""):*; + + function get factory():AnnotationFactory; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/IVersionExtractor.as b/src/com/googlecode/flexxb/core/IVersionExtractor.as new file mode 100644 index 0000000..8dc1952 --- /dev/null +++ b/src/com/googlecode/flexxb/core/IVersionExtractor.as @@ -0,0 +1,37 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + /** + * This interface is used to determine the version of an incoming document. The version + * is considerent consistent throughout the entire document and as such the engine + * will extract it once per received document. + * @author Alexutz + * + */ + public interface IVersionExtractor + { + /** + * Method that returns the version string al located in the source document. Override this + * method to implement different extraction algorithms. + * @param source document + * @return string value representing the document's version + * + */ + function getVersion(source:Object):String; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/MissingFieldDataException.as b/src/com/googlecode/flexxb/core/MissingFieldDataException.as new file mode 100644 index 0000000..84d294f --- /dev/null +++ b/src/com/googlecode/flexxb/core/MissingFieldDataException.as @@ -0,0 +1,15 @@ +package com.googlecode.flexxb.core +{ + /** + * @private + * @author User + * + */ + public final class MissingFieldDataException extends Error + { + public function MissingFieldDataException() + { + super("", 0); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/PropertyResolver.as b/src/com/googlecode/flexxb/core/PropertyResolver.as new file mode 100644 index 0000000..23a7f57 --- /dev/null +++ b/src/com/googlecode/flexxb/core/PropertyResolver.as @@ -0,0 +1,125 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.core +{ + import flash.utils.Dictionary; + + import mx.collections.IList; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * @private + * @author Alexutzutz + * + */ + internal final class PropertyResolver + { + private static const log:ILogger = Log.getLogger("com.googlecode.flexxb.core.Resolver"); + + private var idMap:Dictionary = new Dictionary(); + + [ArrayElementType("ResolverTask")] + private var taskList:Array = []; + + public function PropertyResolver() + { + } + + public function bind(id:String, item:Object):void + { + idMap[id] = item; + } + + public function beginDocument():void + { + } + + public function addResolutionTask(item:Object, field:QName, id:String):void + { + taskList.push(new ResolverTask(item, field, id)); + } + + public function endDocument():void + { + var resolved:Object; + for each(var task:ResolverTask in taskList) + { + resolved = idMap[task.id]; + if (task.object is Array) + { + (task.object as Array).push(resolved); + } + else if (task.object is IList) + { + (task.object as IList).addItem(resolved); + } + else if (task.object != null && task.object.hasOwnProperty(task.field.toString())) + { + task.object[task.field] = resolved; + } + else + { + log.warn("incorrect type: {0} or property: {1}", task.object, task.field) + } + } + + clear(); + } + + + private function clear():void + { + for (var key:* in idMap) + { + delete idMap[key]; + } + + var task:ResolverTask; + var length:uint = taskList.length; + for (var i:uint = 0; i < length; i++) + { + task = taskList[i]; + task.clear(); + } + task = null; + taskList.length = 0; + } + } +} + +class ResolverTask +{ + public var object:Object; + public var field:QName; + public var id:String; + + public function ResolverTask(object:Object, field:QName, id:String) + { + this.object = object; + this.field = field; + this.id = id; + } + + public function clear():void + { + object = null; + field = null; + id = null; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/SerializationCore.as b/src/com/googlecode/flexxb/core/SerializationCore.as new file mode 100644 index 0000000..8cbcadb --- /dev/null +++ b/src/com/googlecode/flexxb/core/SerializationCore.as @@ -0,0 +1,502 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.Stage; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlMember; + import com.googlecode.flexxb.converter.IConverter; + import com.googlecode.flexxb.interfaces.ICycleRecoverable; + import com.googlecode.flexxb.interfaces.ISerializable; + import avmplus.Types; + import com.googlecode.flexxb.util.isNaNFast; + import flash.events.EventDispatcher; + import flash.utils.Dictionary; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * @private + * @author Alexutz + * + */ + public final class SerializationCore extends EventDispatcher + { + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.core.SerializationCore"); + + private static const TRUE:Object = {}; + private var _simpleTypes:Dictionary = new Dictionary(); + private var classMap:Dictionary = new Dictionary(); + private var classNameMap:Dictionary = new Dictionary(); + + public var idResolver:PropertyResolver; + public var descriptorStore:DescriptorStore; + public var configuration:Configuration; + public var collisionDetector:ElementStack; + public var factory:AnnotationFactory; + public var context:XmlDescriptionContext; + + /** + * Constructor + * + */ + public function SerializationCore(context:XmlDescriptionContext, descriptorStore:DescriptorStore) + { + _simpleTypes[Number] = TRUE; + _simpleTypes[int] = TRUE; + _simpleTypes[uint] = TRUE; + _simpleTypes[String] = TRUE; + _simpleTypes[Boolean] = TRUE; + _simpleTypes[Date] = TRUE; + _simpleTypes[XML] = TRUE; + _simpleTypes[Class] = TRUE; + + this.context = context; + this.configuration = context.configuration; + this.factory = descriptorStore.factory; + + this.descriptorStore = descriptorStore; + + this.collisionDetector = new ElementStack(); + this.idResolver = new PropertyResolver(); + } + + + public function get currentObject():Object + { + return collisionDetector.getCurrent(); + } + + /** + * Convert an object to a serialized representation. + * @param object object to be converted. + * @param version + * @param partial + * @return serialized data representation of the given object + */ + public final function serialize(object:*, partial:Boolean = false, version:String = ""):XML + { + if (object == null) + { + return null; + } + + var serializedData:XML; + + object = pushObject(object, partial); + + if (descriptorStore.isCustomSerializable(object)) + { + serializedData = ISerializable(object).serialize(); + } + else + { + var classDescriptor:XmlClass = descriptorStore.getDescriptor(object, version); + serializedData = factory.serialize(object, classDescriptor, null); + var annotation:XmlMember; + if (partial && classDescriptor.idField) + { + doSerialize(object, classDescriptor.idField, serializedData); + } + else + { + for each (annotation in classDescriptor.members) + { + if (annotation.writeOnly || annotation.ignoreOn == Stage.SERIALIZE) + { + continue; + } + doSerialize(object, annotation, serializedData); + } + } + } + + collisionDetector.pop(); + + return serializedData; + } + + public function getObjectId(object:Object):String + { + var classDescriptor:XmlClass = descriptorStore.getDescriptor(object); + if (classDescriptor.idField) + { + return object[classDescriptor.idField.name]; + } + return ""; + } + + private function pushObject(obj:Object, partial:Boolean):Object + { + var collisionDetected:Boolean = !collisionDetector.push(obj); + if (collisionDetected) + { + if (partial) + { + collisionDetector.pushNoCheck(obj); + } + else if (obj is ICycleRecoverable) + { + obj = ICycleRecoverable(obj).onCycleDetected(collisionDetector.getCurrent()); + obj = pushObject(obj, partial); + } + else + { + throw new Error("Cycle detected!"); + } + } + return obj; + } + + /** + * + * @param object + * @param annotation + * @param serializedData + * + */ + private function doSerialize(object:Object, annotation:Annotation, serializedData:XML):void + { + var target:Object = object[annotation.name]; + + if ((target != null && !isNaNFast(target, annotation.type)) || (annotation is XmlMember && XmlMember(annotation).isRequired)) + { + factory.serialize(target, annotation, serializedData); + } + } + + /** + * Convert a serialized data to an AS3 object counterpart + * @param serializedData data to be deserialized + * @param objectClass object class + * @param getFromCache + * @param version + * @return object of type objectClass + * + */ + public final function deserialize(serializedData:XML, objectClass:Class = null, getFromCache:Boolean = false, version:String = ""):* + { + if (serializedData) + { + if (!objectClass) + { + objectClass = context.getIncomingType(serializedData); + } + if (objectClass) + { + var result:*; + var itemId:String; + var foundInCache:Boolean; + var classDescriptor:XmlClass; + var isCustomSerializable:Boolean = descriptorStore.isCustomSerializable(objectClass); + + if (isCustomSerializable) + { + itemId = descriptorStore.getCustomSerializableReference(objectClass).getIdValue(serializedData); + } + else + { + classDescriptor = descriptorStore.getDescriptor(objectClass); + if (factory.getSerializer(classDescriptor.idField)) + { + try + { + itemId = String(factory.deserialize(serializedData, classDescriptor.idField)); + } catch (e:MissingFieldDataException) + { + } + } + } + + //get object from cache + if (configuration.allowCaching && itemId) + { + result = configuration.cacheProvider.getFromCache(itemId, objectClass); + if(result != null) + { + if (getFromCache) + { + return result; + } + else + { + result = configuration.cacheProvider.getFromCache(itemId, objectClass); + foundInCache = result != null; + } + } + } + + + if (!isCustomSerializable) + { + classDescriptor = descriptorStore.getDescriptor(objectClass, version); + } + + if (!foundInCache) + { + //if object is auto processed, get constructor arguments declarations + var contructorArgs:Array; + if (!isCustomSerializable && !classDescriptor.constructor.isDefault) + { + contructorArgs = []; + for each (var member:XmlMember in classDescriptor.constructor.parameterFields) + { + //On deserialization, when using constructor arguments, we need to process them even though the ignoreOn + //flag is set to deserialize stage. + contructorArgs.push(factory.deserialize(serializedData, member)); + } + } + //create object instance + if (configuration.allowCaching) + { + result = configuration.cacheProvider.getNewInstance(objectClass, itemId, contructorArgs); + } + else + { + result = contructorArgs ? getInstance(objectClass, contructorArgs) : new objectClass(); + } + } + + if (itemId) + { + idResolver.bind(itemId, result); + } + + collisionDetector.pushNoCheck(result); + + //update object fields + if (isCustomSerializable) + { + var tmp:Object = ISerializable(result).deserialize(serializedData); + //if they return null then it suks. Keep the original reference See Issue 47: http://code.google.com/p/flexxb/issues/detail?id=47 + if (tmp != null) + { + result = tmp as ISerializable; + } + } + else + { + //iterate through anotations + for each (var annotation:XmlMember in classDescriptor.members) + { + if (annotation.readOnly || classDescriptor.constructor.hasParameterField(annotation)) + { + continue; + } + if (annotation.ignoreOn == Stage.DESERIALIZE) + { + // Let's keep the old behavior for now. If the ignoreOn flag is set on deserialize, + // the field's value is set to null. + // TODO: check if this can be removed + result[annotation.name] = null; + } + else + { + try + { + result[annotation.name] = factory.deserialize(serializedData, annotation); + } catch (e:MissingFieldDataException) + { + //catch this and continue silently because it is thrown only when a field's data is + //missing from the serialized source and ignoreMissingField flag is set to true. + } + } + } + } + collisionDetector.pop(); + + return result; + } + } + return null; + } + + public function beginSerialize():void + { + collisionDetector.beginDocument(); + } + + public function endSerialize():void + { + collisionDetector.endDocument(); + } + + public function beginDeserialise():void + { + idResolver.beginDocument(); + collisionDetector.beginDocument(); + } + + public function endDeserialise():void + { + idResolver.endDocument(); + collisionDetector.endDocument(); + } + + + public function registerSimpleTypeConverter(converter:IConverter, overrideExisting:Boolean = false):Boolean + { + if (converter == null || converter.type == null) + { + return false; + } + if (!overrideExisting && classMap && classMap[converter.type]) + { + return false; + } + classMap[converter.type] = converter; + var className:String = Types.getQualifiedClassName(converter.type); + classNameMap[className] = converter; + _simpleTypes[className] = TRUE; + return true; + } + + public function get simpleTypes():Dictionary + { + return _simpleTypes; + } + + public final function stringToObject(value:String, clasz:Class):* + { + var converter:IConverter = classMap[clasz]; + if (converter != null) + { + return converter.fromString(value); + } + if (value == null) + return null; + if (clasz == Boolean) + { + return (value && value.toLowerCase() == "true"); + } + if (clasz == Date) + { + if (value == "") + { + return null; + } + var date:Date = new Date(); + date.setTime(Date.parse(value)); + return date; + } + return clasz(value); + } + + public final function objectToString(object:*, clasz:Class):String + { + var converter:IConverter = classMap[clasz]; + if (converter != null) + { + return converter.toString(object); + } + if (clasz == String) + { + return object; + } + try + { + return object.toString(); + } catch (e:Error) + { + //should we do something here? I guess not + } + return ""; + } + + public final function xmlToObject(value:XML, clasz:Class):* + { + var converter:IConverter = classMap[clasz]; + + if (converter != null) + { + var string:String; + if(clasz == XML) + { + string = value.toXMLString(); + string = string.substring(string.indexOf(">") + 1, string.lastIndexOf("<") - 1) + } + else + { + string = value.toString(); + } + return converter.fromString(string); + } + else if (value == null) + { + return null; + } + else if (clasz == String) + { + return value.toString(); + } + else if (clasz == Boolean) + { + return value.toString().toLowerCase() == "true"; + } + else if (clasz == Date) + { + if (value == "") + { + return null; + } + var date:Date = new Date(); + date.setTime(Date.parse(value.text().toString())); + return date; + } + + return clasz(value); + } + + + private function getInstance(clasz:Class, args:Array = null):Object + { + if (!args) + { + args = []; + } + switch (args.length) + { + case 0: + return new clasz(); + case 1: + return new clasz(args[0]); + case 2: + return new clasz(args[0], args[1]); + case 3: + return new clasz(args[0], args[1], args[2]); + case 4: + return new clasz(args[0], args[1], args[2], args[3]); + case 5: + return new clasz(args[0], args[1], args[2], args[3], args[4]); + case 6: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + case 8: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + case 9: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); + case 10: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); + default: + return null; + } + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/XmlDescriptionContext.as b/src/com/googlecode/flexxb/core/XmlDescriptionContext.as new file mode 100644 index 0000000..b65baf0 --- /dev/null +++ b/src/com/googlecode/flexxb/core/XmlDescriptionContext.as @@ -0,0 +1,227 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlAttribute; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlNamespace; + import com.googlecode.flexxb.annotation.contract.Constants; + import com.googlecode.flexxb.annotation.contract.ConstructorArgument; + import com.googlecode.flexxb.api.XmlApiArray; + import com.googlecode.flexxb.api.XmlApiAttribute; + import com.googlecode.flexxb.api.XmlApiClass; + import com.googlecode.flexxb.api.XmlApiElement; + import com.googlecode.flexxb.api.XmlApiNamespace; + import com.googlecode.flexxb.converter.ClassTypeConverter; + import com.googlecode.flexxb.converter.IConverter; + import com.googlecode.flexxb.converter.XmlConverter; + import com.googlecode.flexxb.serializer.XmlArraySerializer; + import com.googlecode.flexxb.serializer.XmlAttributeSerializer; + import com.googlecode.flexxb.serializer.XmlClassSerializer; + import com.googlecode.flexxb.serializer.XmlElementSerializer; + import com.googlecode.flexxb.util.XmlUtils; + + import flash.utils.Dictionary; + + /** + * + * @author Alexutz + * + */ + public final class XmlDescriptionContext + { + public var store:DescriptorStore; + public var serializer:SerializationCore; + private var classNamespaceMap:Dictionary = new Dictionary(); + + public var configuration:Configuration; + + public function XmlDescriptionContext() + { + configuration = new Configuration(); + } + + public final function initializeContext(descriptorStore:DescriptorStore, core:SerializationCore):void + { + this.store = descriptorStore; + this.serializer = core; + + registerSimpleTypeConverter(new ClassTypeConverter()); + registerSimpleTypeConverter(new XmlConverter()); + + //register the annotations we know must always exist + registerAnnotation(ConstructorArgument.ANNOTATION_CONSTRUCTOR_ARGUMENT, ConstructorArgument, null); + registerAnnotation(XmlAttribute.ANNOTATION_NAME, XmlAttribute, XmlAttributeSerializer); + registerAnnotation(XmlElement.ANNOTATION_NAME, XmlElement, XmlElementSerializer); + registerAnnotation(XmlArray.ANNOTATION_NAME, XmlArray, XmlArraySerializer); + registerAnnotation(XmlClass.ANNOTATION_NAME, XmlClass, XmlClassSerializer); + registerAnnotation(XmlConstants.ANNOTATION_NAMESPACE, XmlNamespace, null); + + setApiClasses(XmlApiClass, XmlApiArray, XmlApiAttribute, XmlApiElement, XmlApiNamespace); + } + + + public function handleDescriptors(descriptors:Array):void + { + for each(var classDescriptor:XmlClass in descriptors) + { + //if the class descriptor defines a namespace, register it in the namespace map + if (classDescriptor.nameSpace) + { + classNamespaceMap[classDescriptor.nameSpace.uri] = classDescriptor.type; + } + } + } + + /** + * + * @param object + * @return + * + */ + public function getNamespace(object:Object, version:String = ""):Namespace + { + if (object) + { + var desc:XmlClass = store.getDescriptor(object, version) as XmlClass; + if (desc) + { + return desc.nameSpace; + } + } + return null; + } + + /** + * + * @param object + * @return + * + */ + public function getXmlName(object:Object, version:String = ""):QName + { + if (object != null) + { + var classDescriptor:XmlClass = store.getDescriptor(object, version); + if (classDescriptor) + { + return classDescriptor.xmlName; + } + } + return null; + } + + + public function getIncomingType(source:Object):Class + { + var incomingXML:XML = source as XML; + if (incomingXML) + { + if (configuration.getResponseTypeByXsiType) + { + var xsiType:String = incomingXML.attribute(XmlUtils.xsiType).toString(); + if (xsiType) + { + //check if xsiType contains a qualified reference (e.g. xsi:type="a:Item") + if (xsiType.indexOf(":") != -1) + { + //this will return the first XMLCLass alias match irrespective of namespace. + //In order to check more accurately (e.g. match by xmlName) descriptorStore.getClassReferenceByCriteria + //would need to support values other than strings + xsiType = xsiType.split(":")[1]; + } + clasz = store.getClassReferenceByCriteria("alias", xsiType, ""); + if (clasz) + { + return clasz; + } + } + } + if (configuration.getResponseTypeByTagName) + { + var tagName:QName = incomingXML.name() as QName; + if (tagName) + { + var clasz:Class = store.getClassReferenceByCriteria("alias", tagName.localName, ""); + if (clasz) + { + return clasz; + } + } + } + if (configuration.getResponseTypeByNamespace) + { + if (incomingXML.namespaceDeclarations().length > 0) + { + var _namespace:String = (incomingXML.namespaceDeclarations()[0] as Namespace).uri; + return classNamespaceMap[_namespace]; + } + } + } + return null; + } + + /** + * Register a converter instance for a specific type + * @param converter converter instance + * @param overrideExisting override existing registrations under the same class type + * @return + * + */ + public final function registerSimpleTypeConverter(converter:IConverter, overrideExisting:Boolean = false):Boolean + { + return serializer.registerSimpleTypeConverter(converter, overrideExisting); + } + + public final function getSimpleTypes():Dictionary + { + return serializer.simpleTypes; + } + + /** + * Register a new annotation and its serializer. If it finds a registration with the + * same name and overrideExisting is set to false, it will disregard the current attempt and keep the old value. + * @param name the name of the annotation to be registered + * @param annotationClazz annotation class type + * @param serializerInstance instance of the serializer that will handle this annotation + * @param overrideExisting override existing registrations under the same name + * + */ + public final function registerAnnotation(name:String, annotationClazz:Class, serializer:Class, overrideExisting:Boolean = false):void + { + store.factory.registerAnnotation(name, annotationClazz, serializer, this, overrideExisting); + } + + /** + * Specify api classes that reflect the defined annotations. + * @param args + */ + public final function setApiClasses(...args):void + { + for each(var type:Class in args) + { + if (type is Class) + { + store.getDescriptor(type); + } + } + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/core/XmlVersionExtractor.as b/src/com/googlecode/flexxb/core/XmlVersionExtractor.as new file mode 100644 index 0000000..e00b0e4 --- /dev/null +++ b/src/com/googlecode/flexxb/core/XmlVersionExtractor.as @@ -0,0 +1,69 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.core +{ + /** + * This class is used to determine the version of an incoming document. The version + * is considerent consistent throughout the entire document and as such the engine + * will extract it once per received document. By default, the version extractor + * searches for an attribute named "version".
+ * If you require another kind of processing for versions you should extend this + * class and override the getVersion method which returns a String and + * accepts the xml document as source + * @author Alexutz + * + */ + public class XmlVersionExtractor implements IVersionExtractor + { + private var isElement:Boolean; + + private var versionTagName:String; + + /** + * Constructor + * @param versionTagName name of the version tag + * @param isElement boolean flag signaling whether the version is represented as an element or an attribute + * + */ + public function XmlVersionExtractor(versionTagName:String = "version", isElement:Boolean = false) + { + this.versionTagName = versionTagName; + this.isElement = isElement; + } + + /** + * Method that returns the version string al located in the source xml document. Override this + * method to implement different extraction algorithms. + * @param source xml document + * @return string value representing the document's version + * + */ + public function getVersion(source:Object):String + { + var version:String; + if (isElement) + { + version = (source as XML).child(versionTagName); + } + else + { + version = (source as XML).@[versionTagName]; + } + return version; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/error/ApiError.as b/src/com/googlecode/flexxb/error/ApiError.as new file mode 100644 index 0000000..8cf6511 --- /dev/null +++ b/src/com/googlecode/flexxb/error/ApiError.as @@ -0,0 +1,35 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.error +{ + + /** + * This error is thrown when the FlexXB API engine encounters execution problems. + * @author Alexutz + * + */ + public class ApiError extends Error + { + public static const API_COMPONENT_TREE_BUILD_ERROR:int = 0; + + public function ApiError(message:String = "", id:int = 0) + { + super(message, id); + } + + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/error/DescriptorParsingError.as b/src/com/googlecode/flexxb/error/DescriptorParsingError.as new file mode 100644 index 0000000..0184167 --- /dev/null +++ b/src/com/googlecode/flexxb/error/DescriptorParsingError.as @@ -0,0 +1,92 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.error +{ + /** + * Error thrown when the FlexXB engine encounters problems parsing the type descriptor xml + * @author Alexutz + * + */ + public class DescriptorParsingError extends Error + { + /** + * + */ + public static const DESCRIPTOR_PARSING_ERROR_ID:int = 0; + + private var _type:Class; + + private var _fieldName:String; + + /** + * + * @param type + * @param field + * @param message + * + */ + public function DescriptorParsingError(type:Class, field:String, message:String = "") + { + super(message, DESCRIPTOR_PARSING_ERROR_ID); + _type = type; + _fieldName = field; + } + + /** + * + * @return + * + */ + public function get type():Class + { + return _type; + } + + /** + * + * @return + * + */ + public function get field():String + { + return _fieldName; + } + + /** + * + * @return + * + */ + public function toString():String + { + var error:String = "Error encountered while processing the descriptor "; + if (type) + { + error += "for type " + type; + } + if (field) + { + error += " (field " + field + ")"; + } + if (message) + { + error += ":\n" + message; + } + return error; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/interfaces/ICycleRecoverable.as b/src/com/googlecode/flexxb/interfaces/ICycleRecoverable.as new file mode 100644 index 0000000..a899298 --- /dev/null +++ b/src/com/googlecode/flexxb/interfaces/ICycleRecoverable.as @@ -0,0 +1,42 @@ +/** + * FlexXB + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb.interfaces +{ + /** + * Optional interface that can be implemented by FlexXB bound objects to handle + * cycles in the object graph. + *

Normally a cycle in the object graph causes the engine to throw an error. + * This is not always a desired behavior.Implementing this interface allows the + * user application to change this behavior. + * + * @author Alexutz + * + */ + public interface ICycleRecoverable + { + /** + * Called when a cycle is detected by the engine to nominate a new + * object to be serialized instead. + * @param parentCaller reference to the parent object referencing the current one + * @return the object to be serialized instead of this or null to + * instruct the engine to behave as if the object does not implement this interface. + * + */ + function onCycleDetected(parentCaller:Object):Object; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/interfaces/IIdentifiable.as b/src/com/googlecode/flexxb/interfaces/IIdentifiable.as new file mode 100644 index 0000000..fcdd522 --- /dev/null +++ b/src/com/googlecode/flexxb/interfaces/IIdentifiable.as @@ -0,0 +1,41 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.interfaces +{ + + /** + * Provides a method to uniquely identify objects of a certain type. + * @author Alexutz + * + */ + public interface IIdentifiable + { + /** + * Get object id + * @return id + * + */ + function get id():String; + + /** + * Return the current object's type + * @return + * + */ + function get thisType():Class; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/interfaces/ISerializable.as b/src/com/googlecode/flexxb/interfaces/ISerializable.as new file mode 100644 index 0000000..fb36e3e --- /dev/null +++ b/src/com/googlecode/flexxb/interfaces/ISerializable.as @@ -0,0 +1,50 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.interfaces +{ + + /** + * Interface for an object that requires custom serialization/deserialization into/from + * a serialization format (XML, JSON, AMF etc.). Use this interface to instruct the engine + * to delegate the serialization/deserialization task to the object itself. + * @author aciobanu + * + * + */ + public interface ISerializable extends IIdentifiable + { + /** + * Serialize current object into a serialization format + */ + function serialize():XML; + + /** + * Deserialize this object from its serialized representation. + * @param source serialized data source + */ + function deserialize(source:XML):*; + + /** + * Extract the object's identifier from the serialized source if + * such an identifier exists. + * @param source serialized data source + * @return string representing object's identifier + * + */ + function getIdValue(source:XML):String; + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/serializer/BaseSerializer.as b/src/com/googlecode/flexxb/serializer/BaseSerializer.as new file mode 100644 index 0000000..b9ecdb7 --- /dev/null +++ b/src/com/googlecode/flexxb/serializer/BaseSerializer.as @@ -0,0 +1,102 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.serializer +{ + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.core.Configuration; + import com.googlecode.flexxb.core.MissingFieldDataException; + import com.googlecode.flexxb.core.SerializationCore; + import com.googlecode.flexxb.core.XmlDescriptionContext; + import com.googlecode.flexxb.util.cdata; + + import flash.utils.Dictionary; + import flash.xml.XMLNode; + import flash.xml.XMLNodeType; + + /** + * + * @author Alexutz + * + */ + public class BaseSerializer + { + protected static const missingFieldDataException:MissingFieldDataException = new MissingFieldDataException(); + + protected var context:XmlDescriptionContext; + + protected var configuration:Configuration; + + protected var simpleTypes:Dictionary; + + protected var serializer:SerializationCore; + + public function BaseSerializer(context:XmlDescriptionContext) + { + this.context = context; + this.configuration = context.configuration; + this.simpleTypes = context.getSimpleTypes(); + this.serializer = context.serializer; + } + + /** + * Serialize an object into a serialization format + * @param object Object to be serialized + * @param annotation Annotation containing the conversion parameters + * @param serializedData Serialized data written so far + * @serializer + * @return Generated serialized data + * + */ + public function serialize(object:*, annotation:Annotation, serializedData:XML):XML + { + return null; + } + + /** + * Deserialize an xml into the appropiate AS3 object + * @param xmlData Xml to be deserialized + * @param annotation Annotation containing the conversion parameters + * @serializer + * @return Generated object + * + */ + public function deserialize(serializedData:XML, annotation:Annotation):* + { + return null; + } + + protected final function signalMissingField():void + { + if (configuration.ignoreMissingContent) + { + throw missingFieldDataException; + } + } + + protected final function escapeValue(value:*):XML + { + if (configuration.escapeSpecialChars) + { + return new XML(new XMLNode(XMLNodeType.TEXT_NODE, value)); + } + else + { + return cdata(value); + } + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/serializer/XmlArraySerializer.as b/src/com/googlecode/flexxb/serializer/XmlArraySerializer.as new file mode 100644 index 0000000..d6f028b --- /dev/null +++ b/src/com/googlecode/flexxb/serializer/XmlArraySerializer.as @@ -0,0 +1,264 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.serializer +{ + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlMember; + import com.googlecode.flexxb.core.XmlDescriptionContext; + import avmplus.Types; + import com.googlecode.flexxb.util.XmlUtils; + import mx.collections.ArrayCollection; + import mx.collections.ArrayList; + import mx.collections.ListCollectionView; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * Insures serialization/deserialization for object field decorated with the XmlArray annotation. + * @author Alexutz + * + */ + public final class XmlArraySerializer extends XmlMemberSerializer + { + + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.serializer.XmlArraySerializer"); + + /** + *Constructor + * + */ + public function XmlArraySerializer(context:XmlDescriptionContext) + { + super(context); + } + + protected override function serializeObject(object:*, annotation:XmlMember, parentXml:XML):void + { + var result:XML = XmlUtils.template.copy(); + var xmlArray:XmlArray = annotation as XmlArray; + var child:XML; + if (object is ArrayList) + { + object = object.source; + } + + //todo this is incorrect if getRuntimeType is set + var elementType:Class = xmlArray.memberType; + if(elementType == null && object != null && object.length > 0 && object[0] != null) + { + elementType = object[0] != null ? object[0].constructor: null; + } + + for each (var member:Object in object) + { + if (xmlArray.isIDRef) + { + child = new XML(serializer.getObjectId(member)); + if (xmlArray.memberName) + { + var temp:XML = XmlUtils.template.copy(); + temp.setName(xmlArray.memberName); + temp.appendChild(child); + child = temp; + } + } + else if ((elementType == null && member!= null && simpleTypes[Types.getDefinitionByName(Types.getQualifiedClassName(member)) as Class] == null)|| + elementType != null && simpleTypes[elementType] == null) + { + child = serializer.serialize(member, xmlArray.serializePartialElement, annotation.version); + if (xmlArray.memberName) + { + if (annotation.hasNamespaceDeclaration) + { + //need to set a qualified name for the member element + var xmlMemberName:QName = new QName(annotation.nameSpace.uri, xmlArray.memberName.localName); + child.setName(xmlMemberName); + } + else + { + child.setName(xmlArray.memberName); + } + } + } + else + { + var stringValue:String = serializer.objectToString(member, xmlArray.memberType); + var xmlValue:XML; + try + { + xmlValue = new XML(stringValue); + } + catch (error:Error) + { + xmlValue = escapeValue(stringValue); + } + + if (xmlArray.memberName) + { + child = XmlUtils.template.copy(); + child.setName(xmlArray.memberName); + child.appendChild(xmlValue); + } + else + { + child = xmlValue; + } + } + //If the setXsiType flag is set then we should add an xsi:type attribuute to + //the child being created now. Means we expect a derived class object. + if (XmlArray(annotation).setXsiType) + { + child.addNamespace(XmlUtils.xsiNamespace); + var childAnnotation:XmlClass = serializer.descriptorStore.getDescriptor(member, annotation.version) as XmlClass; + if (childAnnotation.hasNamespaceDeclaration) + { + //if child has namespace, then xsi type needs to include it + child.addNamespace(childAnnotation.nameSpace); + child.@[XmlUtils.xsiType] = childAnnotation.nameSpace.prefix + ":" + childAnnotation.alias; + } + else + { + child.@[XmlUtils.xsiType] = childAnnotation.alias; + } + } + result.appendChild(child); + } + if (xmlArray.useOwnerAlias) + { + for each (var subChild:XML in result.children()) + { + parentXml.appendChild(subChild); + } + } + else + { + result.setName(xmlArray.xmlName); + parentXml.appendChild(result); + } + } + + protected override function deserializeObject(xmlData:XML, xmlName:QName, element:XmlMember):* + { + var result:Object = new element.type(); + + var array:XmlArray = element as XmlArray; + + var xmlArray:XMLList; + //get the xml list representing the array + if (array.useOwnerAlias) + { + if (array.memberName) + { + xmlName = array.memberName; + xmlArray = xmlData.child(xmlName); + } + else if (array.memberType) + { + xmlName = context.getXmlName(array.memberType); + xmlArray = xmlData.child(xmlName); + } + else + { + xmlArray = xmlData.children(); + } + } + else + { + xmlName = array.xmlName; + xmlArray = xmlData.child(xmlName); + if (xmlArray.length() > 0) + { + xmlArray = xmlArray.children(); + } + else + { + xmlArray = null; + } + } + //extract the items from xml, build the result array and return it + + //todo better way for empty collections + if (!xmlArray /*|| xmlArray.length() == 0*/) + { + signalMissingField(); + return result; + } + var list:Array = []; + if (!array.memberName && xmlArray.length() == 1 && xmlArray[0].nodeKind() == "text") + { + // we need to handle differently the case in which we have items of simple type + // and have no item name defined + var values:Array = xmlArray[0].toString().split("\n"); + for each (var value:String in values) + { + list.push(simpleTypes[array.memberType] == null ? serializer.deserialize(new XML(value), array.memberType, array.getFromCache, array.version) : serializer.stringToObject(value, array.memberType)); + } + } + else + { + var type:Class = array.memberType; + for each (var xmlChild:XML in xmlArray) + { + if (array.getRuntimeType) + { + type = context.getIncomingType(xmlChild); + if (!type) + { + type = array.memberType; + } + } + if (array.isIDRef) + { + serializer.idResolver.addResolutionTask(list, null, xmlChild.toString()); + } + else + { + var member:Object = simpleTypes[type] == null ? serializer.deserialize(xmlChild, type, array.getFromCache, array.version) : serializer.xmlToObject(xmlChild, type); + if (member != null) + { + list.push(member); + } + } + } + } + + if (element.type == Array) + { + result.push.apply(null, list); + } + else if (element.type == ArrayCollection || element.type == ArrayList) + { + result.source = list; + } + else if (result is ListCollectionView) + { + result.list = new ArrayList(list); + } + else if (Types.getQualifiedClassName(element.type).indexOf("__AS3__.vec::Vector") == 0) + { + result.push.apply(null, list); + } + else + { + throw new Error("Unsupported type: " + Types.getQualifiedClassName(result)) + } + + return result; + } + } +} diff --git a/src/com/googlecode/flexxb/serializer/XmlAttributeSerializer.as b/src/com/googlecode/flexxb/serializer/XmlAttributeSerializer.as new file mode 100644 index 0000000..6710f9a --- /dev/null +++ b/src/com/googlecode/flexxb/serializer/XmlAttributeSerializer.as @@ -0,0 +1,86 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.serializer +{ + import com.googlecode.flexxb.annotation.contract.XmlMember; + import com.googlecode.flexxb.core.XmlDescriptionContext; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * Insures serialization/deserialization for object field decorated with the XmlAttribute annotation + * @author Alexutz + * + */ + public final class XmlAttributeSerializer extends XmlMemberSerializer + { + + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.serializer.XmlAttributeSerializer"); + + /** + * Constructor + * + */ + public function XmlAttributeSerializer(context:XmlDescriptionContext) + { + super(context); + } + + protected override function serializeObject(object:*, attribute:XmlMember, parentXml:XML):void + { + var value:String; + if (simpleTypes[attribute.type] == null && attribute.isIDRef) + { + value = serializer.getObjectId(object); + } + else + { + value = serializer.objectToString(object, attribute.type); + } + parentXml.@[attribute.xmlName] = value; + } + + protected override function deserializeObject(xmlData:XML, xmlName:QName, attribute:XmlMember):* + { +// if (Log.isDebug()) +// { +// LOG.debug("Deserializing attribute <<{0}>> to field {1}", xmlName, attribute.name); +// } + var valueXML:XMLList = xmlData.attribute(xmlName); + var value:String = ""; + if (valueXML.length() > 0) + { + value = valueXML[0]; + } + else + { + signalMissingField(); + value = attribute.defaultSetValue; + } + var result:Object; + if (attribute.isIDRef) + { + serializer.idResolver.addResolutionTask(serializer.currentObject, attribute.name, value); + } + else + { + result = serializer.stringToObject(value, attribute.type); + } + return result; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/serializer/XmlClassSerializer.as b/src/com/googlecode/flexxb/serializer/XmlClassSerializer.as new file mode 100644 index 0000000..0a68b5d --- /dev/null +++ b/src/com/googlecode/flexxb/serializer/XmlClassSerializer.as @@ -0,0 +1,85 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.serializer +{ + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlMember; + import com.googlecode.flexxb.core.XmlDescriptionContext; + import com.googlecode.flexxb.util.XmlUtils; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * + * @author Alexutz + * + */ + public final class XmlClassSerializer extends BaseSerializer + { + + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.serializer.XmlClassSerializer"); + + public function XmlClassSerializer(context:XmlDescriptionContext) + { + super(context); + } + + public override function serialize(object:*, annotation:Annotation, serializedData:XML):XML + { + var xmlClass:XmlClass = annotation as XmlClass; +// if (Log.isDebug()) +// { +// LOG.debug("Serializing object of type {0}", xmlClass.name); +// } + var xml:XML = XmlUtils.template.copy(); + var cursor:XML = xml; + if (xmlClass.isPath) + { + cursor = XmlUtils.setPathElement(xmlClass, xml); + xml = xml.children()[0]; + cursor.appendChild(XmlUtils.template.copy()); + cursor = cursor.children()[0]; + } + cursor.setNamespace(xmlClass.nameSpace); + cursor.setName(new QName(xmlClass.nameSpace, xmlClass.alias)); + + if (xmlClass.useOwnNamespace) + { + xml.addNamespace(xmlClass.nameSpace); + } + else + { + var member:XmlMember = xmlClass.getMember(xmlClass.childNameSpaceFieldName); + if (member) + { + var ns:Namespace = context.getNamespace(object[member.name]); + if (ns) + { + xml.addNamespace(ns); + } + } + } + return xml; + } + + public override function deserialize(serializedData:XML, annotation:Annotation):* + { + return null; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/serializer/XmlElementSerializer.as b/src/com/googlecode/flexxb/serializer/XmlElementSerializer.as new file mode 100644 index 0000000..80b2639 --- /dev/null +++ b/src/com/googlecode/flexxb/serializer/XmlElementSerializer.as @@ -0,0 +1,197 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.serializer +{ + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlMember; + import com.googlecode.flexxb.core.XmlDescriptionContext; + import com.googlecode.flexxb.util.XmlUtils; + import com.googlecode.flexxb.util.cdata; + import mx.logging.ILogger; + import mx.logging.Log; + + /** + * Insures serialization/deserialization for object field decorated with the XmlElement annotation + * @author Alexutz + * + */ + public class XmlElementSerializer extends XmlMemberSerializer + { + private static const LOG:ILogger = Log.getLogger("com.googlecode.flexxb.serializer.XmlElementSerializer"); + + /** + * Constructor + * + */ + public function XmlElementSerializer(context:XmlDescriptionContext) + { + super(context); + } + + protected override function serializeObject(object:*, annotation:XmlMember, parentXml:XML):void + { + var child:XML = XmlUtils.template.copy(); + + var xmlElement:XmlElement = XmlElement(annotation); + + if (object == null) + { + if (xmlElement.nillable) + { + child.addNamespace(XmlUtils.xsiNamespace); + child.@[XmlUtils.xsiNil] = "true"; + } + } + else if (simpleTypes[annotation.type] == null) + { + if (annotation.isIDRef) + { + child.appendChild(serializer.getObjectId(object)); + } + else + { + child = serializer.serialize(object, xmlElement.serializePartialElement, annotation.version); + } + } + else if (annotation.type == XML) + { + child.appendChild(new XML(object)); + } + else + { + var stringValue:String = serializer.objectToString(object, annotation.type); + try + { + if (xmlElement.wrapCDATA) + { + child.appendChild(cdata(stringValue)); + } + else + { + child.appendChild(stringValue); + } + } catch (error:Error) + { + child.appendChild(escapeValue(stringValue)); + } + } + + if (annotation.useOwnerAlias) + { + var name:QName = context.getXmlName(object, annotation.version); + if (name) + { + child.setName(name); + } + } + else if (annotation.xmlName) + { + child.setName(annotation.xmlName); + } + //If the setXsiType flag is set then we should add an xsi:type attribuute to + //the child being created now. Means we expect a derived class object. + if (xmlElement.setXsiType) + { + child.addNamespace(XmlUtils.xsiNamespace); + var childAnnotation:XmlClass = serializer.descriptorStore.getDescriptor(object, annotation.version); + if (childAnnotation.hasNamespaceDeclaration) + { + //if child has namespace, then xsi type needs to include it + child.addNamespace(childAnnotation.xmlName); + child.@[XmlUtils.xsiType] = childAnnotation.nameSpace.prefix + ":" + childAnnotation.alias; + } + else + { + child.@[XmlUtils.xsiType] = childAnnotation.alias; + } + } + parentXml.appendChild(child); + } + + protected override function deserializeObject(xmlData:XML, xmlName:QName, element:XmlMember):* + { + var xmlElement:XmlElement = XmlElement(element); + + // AFAIK we can have a null xmlName only when getRuntimeType is true and the element + //has a virtual path so the engine can detect the wrapper + var type:Class = xmlElement.type; + + if (xmlElement.getRuntimeType) + { + if (xmlElement.isPath) + { + if (xmlData.children().length() > 0) + { + xmlName = context.getXmlName(context.getIncomingType(xmlData.children()[0])); + } + else + { + signalMissingField(); + return null; + } + } + else + { + //??? Don't know yet what should happen in this case + } + } +// if (Log.isDebug()) +// { +// LOG.debug("Deserializing element <<{0}>> to field {1}", xmlName, xmlElement.name); +// } + var list:XMLList = xmlData.child(xmlName); + var xml:XML; + if (list.length() > 0) + { + xml = list[0]; + } + else + { + if (xmlElement.defaultSetValue) + { + xml = new XML(xmlElement.defaultSetValue); + } + else + { + signalMissingField(); + return null; + } + } + if (xmlElement.isIDRef) + { + serializer.idResolver.addResolutionTask(serializer.currentObject, xmlElement.name, xml.toString()); + return null; + } + + if (xmlElement.nillable && xml.@[XmlUtils.xsiNil] == "true") + { + return null; + } + + if (xmlElement.getRuntimeType) + { + type = context.getIncomingType(list[0]); + if (!type) + { + type = element.type; + } + } + return simpleTypes[type] == null ? serializer.deserialize(xml, type, xmlElement.getFromCache, xmlElement.version) : serializer.xmlToObject(xml, type); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/serializer/XmlMemberSerializer.as b/src/com/googlecode/flexxb/serializer/XmlMemberSerializer.as new file mode 100644 index 0000000..17dfbbe --- /dev/null +++ b/src/com/googlecode/flexxb/serializer/XmlMemberSerializer.as @@ -0,0 +1,140 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.serializer +{ + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlMember; + import com.googlecode.flexxb.core.SerializationCore; + import com.googlecode.flexxb.core.XmlDescriptionContext; + import com.googlecode.flexxb.util.XmlUtils; + import com.googlecode.flexxb.util.cdata; + + /** + * + * @author Alexutz + * + */ + internal class XmlMemberSerializer extends BaseSerializer + { + public function XmlMemberSerializer(context:XmlDescriptionContext) + { + super(context); + } + + public override function serialize(object:*, annotation:Annotation, serializedData:XML):XML + { + var element:XmlMember = annotation as XmlMember; + var parentXml:XML = serializedData as XML; + + + var location:XML = parentXml; + + if (element.isPath) + { + location = XmlUtils.setPathElement(element, parentXml); + } + + if (element.isDefaultValue) + { + //wrapCDATA was not checked here + if(element is XmlElement && XmlElement(element).wrapCDATA) + { + location.appendChild(cdata(serializer.objectToString(object, element.type))); + } + else + { + location.appendChild(serializer.objectToString(object, element.type)); + } + return null; + } + + if (element.hasNamespaceRef && element.nameSpace != element.ownerClass.nameSpace && XmlUtils.mustAddNamespace(element.nameSpace, parentXml)) + { + parentXml.addNamespace(element.nameSpace); + } + + serializeObject(object, element, location); + + return location; + } + + /** + * + * @param object + * @param annotation + * @param serializer + * @return + * + */ + protected function serializeObject(object:*, annotation:XmlMember, parentXml:XML):void + { + } + + public override function deserialize(serializedData:XML, annotation:Annotation):* + { + var element:XmlMember = annotation as XmlMember; + var xmlData:XML = serializedData as XML; + + var xmlElement:XML; + + if (element.isPath) + { + xmlElement = XmlUtils.getPathElement(element, xmlData); + } + else + { + xmlElement = xmlData; + } + + if (xmlElement == null) + { + signalMissingField(); + return null; + } + + if (element.isDefaultValue) + { + for each (var child:XML in xmlElement.children()) + { + if (child.nodeKind() == "text") + { + return serializer.stringToObject(child.toString(), element.type); //fixed CDATA deserialization + } + } + } + + var xmlName:QName; + if (element.useOwnerAlias) + { + xmlName = context.getXmlName(element.type); + } + else + { + xmlName = element.xmlName; + } + + var value:Object = deserializeObject(xmlElement, xmlName, element); + return value; + } + + protected function deserializeObject(xmlData:XML, xmlName:QName, annotation:XmlMember):* + { + return null; + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/util/Instanciator.as b/src/com/googlecode/flexxb/util/Instanciator.as new file mode 100644 index 0000000..f414593 --- /dev/null +++ b/src/com/googlecode/flexxb/util/Instanciator.as @@ -0,0 +1,82 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.util +{ + import avmplus.Types; + + public final class Instanciator + { + public static function getInstanceByName(className:String):Object + { + var clasz:Class = Types.getDefinitionByName(className) as Class; + if (clasz) + { + return getInstance(clasz); + } + return null; + } + + /** + * Dynamically create an instance with runtime known parameters. + * Restricted to max 10(ten) instance parameters. + * TODO: Find a better way to do this!!!!! + * @param clasz + * @param args + * @return + * + */ + public static function getInstance(clasz:Class, args:Array = null):Object + { + if (!args) + { + args = []; + } + switch (args.length) + { + case 0: + return new clasz(); + case 1: + return new clasz(args[0]); + case 2: + return new clasz(args[0], args[1]); + case 3: + return new clasz(args[0], args[1], args[2]); + case 4: + return new clasz(args[0], args[1], args[2], args[3]); + case 5: + return new clasz(args[0], args[1], args[2], args[3], args[4]); + case 6: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + case 8: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]); + case 9: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]); + case 10: + return new clasz(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]); + default: + return null; + } + } + + public function Instanciator() + { + throw new Error("Access static memebers!"); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/util/XmlUtils.as b/src/com/googlecode/flexxb/util/XmlUtils.as new file mode 100644 index 0000000..5631d76 --- /dev/null +++ b/src/com/googlecode/flexxb/util/XmlUtils.as @@ -0,0 +1,109 @@ +package com.googlecode.flexxb.util +{ + import com.googlecode.flexxb.annotation.contract.Annotation; + + public final class XmlUtils + { + public static const template:XML = new XML(""); + + public static const xsiNamespace:Namespace = new Namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + /** + * Qualified name of the xml schema type attribute + */ + public static const xsiType:QName = new QName(xsiNamespace, "type"); + /** + * Qualified name of the xml schema nil attribute + */ + public static const xsiNil:QName = new QName(xsiNamespace, "nil"); + + /** + * + * @param ns + * @param xml + * @return + * + */ + public static function mustAddNamespace(ns:Namespace, xml:XML):Boolean + { + var inScopeNs:Array = xml.inScopeNamespaces(); + for each(var inNs:Namespace in inScopeNs) + { + if (inNs.uri == ns.uri) + { + return false; + } + } + return true; + } + + /** + * + * @param element + * @param xmlData + * @return + * + */ + public static function getPathElement(element:Annotation, xmlData:XML):XML + { + var xmlElement:XML; + var list:XMLList; + var pathElement:QName; + for (var i:int = 0; i < element.qualifiedPathElements.length; i++) + { + pathElement = element.qualifiedPathElements[i]; + if (!xmlElement) + { + list = xmlData.child(pathElement); + } + else + { + list = xmlElement.child(pathElement); + } + if (list.length() > 0) + { + xmlElement = list[0]; + } + else + { + xmlElement = null; + break; + } + } + return xmlElement; + } + + /** + * + * @param element + * @param xmlParent + * @param serializedChild + * @return + * + */ + public static function setPathElement(element:Annotation, xmlParent:XML):XML + { + var cursor:XML = xmlParent; + for each (var pathElement:QName in element.qualifiedPathElements) + { + var path:XMLList = cursor.child(pathElement); + if (path.length() > 0) + { + cursor = path[0]; + } + else + { + var pathItem:XML = XmlUtils.template.copy(); + pathItem.setName(pathElement); + cursor.appendChild(pathItem); + cursor = pathItem; + } + } + return cursor; + } + + public function XmlUtils() + { + throw new Error("Use static members"); + } + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/util/cdata.as b/src/com/googlecode/flexxb/util/cdata.as new file mode 100644 index 0000000..a85dbdd --- /dev/null +++ b/src/com/googlecode/flexxb/util/cdata.as @@ -0,0 +1,29 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.util +{ + /** + * Function that wraps the provided value in an xml with a CDATA tag + * @param value value to which the cdata tag will be added + * @return XML representing the value + * + */ + public function cdata(value:*):XML + { + return new XML(""); + } +} \ No newline at end of file diff --git a/src/com/googlecode/flexxb/util/isNaNFast.as b/src/com/googlecode/flexxb/util/isNaNFast.as new file mode 100644 index 0000000..32bd8e2 --- /dev/null +++ b/src/com/googlecode/flexxb/util/isNaNFast.as @@ -0,0 +1,7 @@ +package com.googlecode.flexxb.util +{ + public function isNaNFast(target:*, type:Class):Boolean + { + return type == Number && (!(target <= 0) && !(target > 0)); + } +} diff --git a/src/metadata.xml b/src/metadata.xml new file mode 100644 index 0000000..a1046ff --- /dev/null +++ b/src/metadata.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testSrc/assets/xml/descriptor.xml b/testSrc/assets/xml/descriptor.xml new file mode 100644 index 0000000..7d15efd --- /dev/null +++ b/testSrc/assets/xml/descriptor.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/CircularReferenceTest.as b/testSrc/com/googlecode/flexxb/CircularReferenceTest.as new file mode 100644 index 0000000..0d4039d --- /dev/null +++ b/testSrc/com/googlecode/flexxb/CircularReferenceTest.as @@ -0,0 +1,120 @@ +/** + * FlexXBTest + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.api.XmlApiClass; + import com.googlecode.testData.Company; + import com.googlecode.testData.Department; + import com.googlecode.testData.DepartmentEmployee; + + import flash.events.Event; + + import org.flexunit.assertThat; + import org.hamcrest.object.equalTo; + import org.hamcrest.object.notNullValue; + + public final class CircularReferenceTest + { + private var cycleDetectedCount:Number; + + public function CircularReferenceTest() + { + } + + [Before] + public function setup():void + { + cycleDetectedCount = 0; + } + + [Test] + public function validateCollisionDetection():void + { + var department:Department = new Department(); + department.id = 14; + department.name = "R&D"; + var employee:DepartmentEmployee = new DepartmentEmployee(); + employee.name = "John Doe"; + employee.department = department; + department.employees = [employee]; + employee = new DepartmentEmployee(); + employee.name = "Mike Chambers"; + employee.department = department; + department.employees.push(employee); + department.addEventListener(Department.CYCLE_DETECTED, onCycleDetected); + var xml:XML = new FxBEngine().getXmlSerializer().serialize(department) as XML; + assertThat(cycleDetectedCount, equalTo(2)); + } + + [Test] + public function circularReferenceTest():void + { + var company:Company = new Company(); + company.departments = []; + company.employees = []; + + var department:Department; + department = new Department(); + department.id = 14; + department.name = "R&D"; + company.departments.push(department); + + var employee:DepartmentEmployee; + employee = new DepartmentEmployee(); + employee.name = "Johnny Quest"; + employee.department = department; + company.employees.push(employee); + + employee = new DepartmentEmployee(); + employee.name = "Johnny Bravo"; + employee.department = department; + company.employees.push(employee); + + department = new Department(); + department.id = 11; + department.name = "Marketing"; + company.departments.push(department); + + employee = new DepartmentEmployee(); + employee.name = "GI Joe"; + employee.department = department; + company.employees.push(employee); + + var engine:FxBEngine = new FxBEngine(); + var clasz:XmlApiClass = new XmlApiClass(DepartmentEmployee); + clasz.addAttribute("name", String); + clasz.addElement("department", Department).idref = true; + engine.api.processTypeDescriptor(clasz); + var xml:XML = engine.getXmlSerializer().serialize(company) as XML; + var clone:Company = engine.getXmlSerializer().deserialize(xml); + + assertThat(clone.departments.length, equalTo(2)); + assertThat(clone.employees.length, equalTo(3)); + assertThat(DepartmentEmployee(clone.employees[0]).department, notNullValue()); + assertThat(DepartmentEmployee(clone.employees[0]).department, equalTo(clone.departments[0])); + assertThat(DepartmentEmployee(clone.employees[1]).department, equalTo(clone.departments[0])); + assertThat(DepartmentEmployee(clone.employees[2]).department, equalTo(clone.departments[1])); + } + + private function onCycleDetected(event:Event):void + { + cycleDetectedCount++; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/NamespaceTest.as b/testSrc/com/googlecode/flexxb/NamespaceTest.as new file mode 100644 index 0000000..f1454f9 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/NamespaceTest.as @@ -0,0 +1,55 @@ +/** + * FlexXBTest + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.flexxb +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.testData.MGM; + import com.googlecode.testData.Node; + + import mx.collections.ArrayCollection; + + import org.flexunit.assertThat; + import org.hamcrest.object.equalTo; + + public class NamespaceTest + { + public function NamespaceTest() + { + } + + [Test] + public function doInternalNamespaceTest():void + { + var node:Node = new Node(); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(node) as XML; + namespace xsi = "http://www.w3.org/2001/XMLSchema-instance"; + assertThat(xml.@xsi::type, equalTo("xml")); + } + + [Test] + public function deEmptyNSTest():void + { + var obj:MGM = new MGM(); + obj.fields = new ArrayCollection(["one", "two", "three"]); + obj.id = "prodhost"; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(obj) as XML; + assertThat(xml.fields.length(), equalTo(1)); + assertThat(xml.id.length(), equalTo(0)); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/PartialSerializationTest.as b/testSrc/com/googlecode/flexxb/PartialSerializationTest.as new file mode 100644 index 0000000..c40b18a --- /dev/null +++ b/testSrc/com/googlecode/flexxb/PartialSerializationTest.as @@ -0,0 +1,49 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.testData.Mock; + import com.googlecode.testData.Mock3; + + import org.flexunit.Assert; + + /** + * + * @author aCiobanu + * + */ + public class PartialSerializationTest + { + + [Test] + public function testPartialSerialization():void + { + var target:Mock = new Mock(); + target.aField = "test"; + target.link = new Mock3(); + target.link.id = 325; + target.link.version = 2; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + var mk3:XML = xml.child(new QName(new Namespace("http://www.test.com/xmlns/pp/v1"), "mock3"))[0]; + Assert.assertTrue(mk3.length() > 0); + Assert.assertEquals("Link id is wrong", "325", mk3.@id); + Assert.assertEquals("Link attribute is wrong", "", mk3.@attribute.toString()); + Assert.assertEquals("Link version is wrong", "", mk3.objectVersion.toString()); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/XmlElementOrderTest.as b/testSrc/com/googlecode/flexxb/XmlElementOrderTest.as new file mode 100644 index 0000000..b8921fc --- /dev/null +++ b/testSrc/com/googlecode/flexxb/XmlElementOrderTest.as @@ -0,0 +1,44 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.testData.NameOrdered; + import org.flexunit.Assert; + + /** + * + * @author Alexutz + * + */ + public class XmlElementOrderTest + { + [Test] + public function testNameOrder():void + { + var test:NameOrdered = new NameOrdered(); + test.test1 = 3; + test.test2 = "valoare"; + test.reference = "ref"; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(test) as XML; + Assert.assertEquals("ChildOrder not ok for first child", "reference", (xml.children()[0] as XML).name().toString()); + Assert.assertEquals("ChildOrder not ok for second child", "test2", (xml.children()[1] as XML).name().toString()); + Assert.assertEquals("ChildOrder not ok for third child", "TestOk", (xml.children()[2] as XML).name().toString()); + Assert.assertEquals("ChildOrder not ok for third child", "variable", (xml.children()[3] as XML).name().toString()); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/XmlSerializerTest.as b/testSrc/com/googlecode/flexxb/XmlSerializerTest.as new file mode 100644 index 0000000..9fe7465 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/XmlSerializerTest.as @@ -0,0 +1,500 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.core.IFlexXB; + import com.googlecode.flexxb.util.XmlUtils; + import com.googlecode.testData.AnotherVP; + import com.googlecode.testData.ArrayListItem; + import com.googlecode.testData.ConstructorRefObj; + import com.googlecode.testData.CustomSerializabeObject; + import com.googlecode.testData.List; + import com.googlecode.testData.Mock; + import com.googlecode.testData.Mock2; + import com.googlecode.testData.Mock3; + import com.googlecode.testData.NamespacedArrayMember; + import com.googlecode.testData.VectoredElement; + import com.googlecode.testData.XmlPathObject; + import com.googlecode.testData.XmlTypedObj; + import com.googlecode.testData.arrayIssue.IData; + import com.googlecode.testData.derivedType.*; + import com.googlecode.testData.errorTest.TestVO; + import com.googlecode.testData.errorTest.testVO6; + import com.googlecode.testData.errorTest.testVO7; + import com.googlecode.testData.idref.Data; + import com.googlecode.testData.idref.Node; + import com.googlecode.testData.xsi.BaseItem; + import com.googlecode.testData.xsi.ItemA; + import com.googlecode.testData.xsi.ItemB; + import com.googlecode.testData.xsi.Main; + import com.googlecode.testData.xsi.nil.NillableData; + + import flash.net.registerClassAlias; + + import mx.collections.ArrayCollection; + import mx.collections.ArrayList; + import mx.utils.ObjectUtil; + + import org.flexunit.Assert; + import org.flexunit.assertThat; + import org.flexunit.asserts.assertEquals; + import org.flexunit.asserts.assertFalse; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertNull; + import org.flexunit.asserts.assertTrue; + import org.hamcrest.object.equalTo; + import org.hamcrest.object.instanceOf; + import org.hamcrest.object.notNullValue; + + public class XmlSerializerTest + { + + protected function getObject():Mock + { + var target:Mock = new Mock(); + target.link = new Mock3(); + target.aField = "test1"; + target.classType = Mock2; + target.date = new Date(); + target.version = 6; + target.result = []; + var mk:Mock = new Mock(); + mk.date = new Date(); + mk.aField = "mocktestfield"; + target.result.push(mk); + return target; + } + + protected function compare(source:Mock, copy:Mock):void + { + assertEquals("Wrong version", source.version, copy.version); + assertEquals("Wrong aField", source.aField, copy.aField); + assertEquals("Wrong link id", source.link.id, copy.link.id); + assertNull("Date not null", copy.date); + assertEquals("Wrong result list", source.result.length, copy.result.length); + assertFalse("Wrong excluded field", copy.someExcludedField); + assertEquals("Wrong type specified", source.classType, copy.classType); + } + + [Test] + public function testSerializeWithNS():void + { + var target:Mock = getObject(); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + var copy:Mock = FxBEngine.instance.getXmlSerializer().deserialize(xml, Mock); + compare(target, copy); + var nss:Array = xml.inScopeNamespaces(); + var str:String = xml.toXMLString().split(nss[0].prefix + ":").join("").split("xmlns:" + nss[0].prefix + "=\"" + nss[0].uri + "\"").join(""); + xml = XML(str); + copy = FxBEngine.instance.getXmlSerializer().deserialize(xml, Mock); + compare(target, copy); + } + + [Test] + public function testXmlTypedFields():void + { + var target:XmlTypedObj = new XmlTypedObj(); + target.firstXml = ; + target.secondXml = + Doe + ; + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + engine.processTypes(XmlTypedObj); + var xml:XML = engine.serialize(target) as XML; + var copy:XmlTypedObj = engine.deserialize(xml, XmlTypedObj); + Assert.assertEquals("firstXml stinks", target.firstXml.toXMLString(), copy.firstXml.toXMLString()); + Assert.assertEquals("secondXml stinks", target.secondXml.toXMLString(), copy.secondXml.toXMLString()); + } + + [Test] + public function testCustomConstructor():void + { + var target:ConstructorRefObj = new ConstructorRefObj("test", 1, true); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + var copy:ConstructorRefObj = FxBEngine.instance.getXmlSerializer().deserialize(xml, ConstructorRefObj); + Assert.assertEquals("Ref1 is different", target.ref1, copy.ref1); + Assert.assertEquals("Ref2 is different", target.ref2, copy.ref2); + Assert.assertEquals("Ref3 is different", target.ref3, copy.ref3); + } + + [Test] + public function testSerializeWithoutNS():void + { + var target:Mock3 = new Mock3(); + target.attribute = true; + target.id = 5; + target.version = 33; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + var copy:Mock3 = FxBEngine.instance.getXmlSerializer().deserialize(xml, Mock3); + Assert.assertEquals("Attribute is wrong", target.attribute, copy.attribute); + Assert.assertEquals("id is wrong", target.id, copy.id); + Assert.assertEquals("version is wrong", target.version, copy.version); + } + + [Test] + public function testSimpleTypedArrays():void + { + var tst:List = new List(); + tst.nums.push(1, 2, 3, 4); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(tst) as XML; + var copy:List = FxBEngine.instance.getXmlSerializer().deserialize(xml, List); + Assert.assertEquals("Length does not match", tst.nums.length, copy.nums.length); + var i:int = 0; + while (i < tst.nums.length) + { + Assert.assertEquals("Element " + i + " does not match", tst.nums[i], copy.nums[i++]); + } + } + + [Test] + public function verifySimpleTypedNoWrapperArrays():void + { + var list:List = new List(); + list.items = ["one", "two", "three"]; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(list) as XML; + var copy:List = FxBEngine.instance.getXmlSerializer().deserialize(xml, List); + Assert.assertEquals("Item count is incorrect", 3, copy.items.length); + xml = + + one + two + three + + + 1 + 2 + 3 + + ; + copy = FxBEngine.instance.getXmlSerializer().deserialize(xml, List); + Assert.assertEquals("Item count is incorrect", 3, copy.items.length); + Assert.assertEquals("Numbers count is incorrect", 3, copy.numbers.length); + } + + [Test] + public function testVirtualPath():void + { + var target:XmlPathObject = new XmlPathObject(); + target.defaultTest = "My custom default"; + target.identity = 345; + target.reference = "SOmeRef"; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + var copy:XmlPathObject = FxBEngine.instance.getXmlSerializer().deserialize(xml, XmlPathObject); + Assert.assertEquals("Identity is wrong", target.identity, copy.identity); + Assert.assertEquals("Reference is wrong", target.reference, copy.reference); + Assert.assertEquals("DefaultTest is wrong", target.defaultTest, copy.defaultTest); + registerClassAlias("com.googlecode.testData.XmlPathObject", XmlPathObject); + xml = FxBEngine.instance.getXmlSerializer().serialize(ObjectUtil.copy(target)) as XML; + } + + [Test] + public function testNestedVirtualPathWithClassAlias():void + { + var newTarget:AnotherVP = new AnotherVP(); + newTarget.path = new XmlPathObject(); + newTarget.path.defaultTest = "My custom default"; + newTarget.path.identity = 345; + newTarget.path.reference = "SOmeRef"; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(newTarget) as XML; + var copy:AnotherVP = FxBEngine.instance.getXmlSerializer().deserialize(xml, AnotherVP); + Assert.assertEquals("Id is wrong", newTarget.id, copy.id); + Assert.assertEquals("Identity is wrong", newTarget.path.identity, copy.path.identity); + Assert.assertEquals("Reference is wrong", newTarget.path.reference, copy.path.reference); + Assert.assertEquals("DefaultTest is wrong", newTarget.path.defaultTest, copy.path.defaultTest); + } + + [Test] + public function testNamespaceNestedArray():void + { + var xml:XML = + + + + + + + ; + var data:IData = FxBEngine.instance.getXmlSerializer().deserialize(xml, IData); + assertThat(data.localItems.length, equalTo(2)); + assertThat(data.nestedItems.length, equalTo(2)); + } + + [Test] + public function testClassTypeByNamespace():void + { + var target:Mock2 = new Mock2(); + target.id = 512; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + var copy:Object = FxBEngine.instance.getXmlSerializer().deserialize(xml); + Assert.assertTrue("copy is null or not mock2", copy is Mock2); + } + + [Test] + public function testCustomSerialization():void + { + var target:CustomSerializabeObject = new CustomSerializabeObject(); + target.test = "acesta este un test"; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + Assert.assertNotNull("Empty xml!", xml); + var result:CustomSerializabeObject = FxBEngine.instance.getXmlSerializer().deserialize(xml, CustomSerializabeObject); + Assert.assertEquals("Wrong test field values", target.test, result.test); + + } + + [Test] + public function testVectorTypeFields():void + { + var item:VectoredElement = new VectoredElement(); + item.id = "test"; + item.list = new Vector.(); + item.list.push("one", "two", "ten"); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(item) as XML; + var clone:VectoredElement = FxBEngine.instance.getXmlSerializer().deserialize(xml, VectoredElement); + assertThat(clone.id, equalTo(item.id)); + assertNotNull(clone.list); + assertThat(clone.list.length, equalTo(item.list.length)); + for (var i:int = 0; i < item.list.length; i++) + { + assertThat(clone.list[i], equalTo(item.list[i])); + } + } + + [Test] + public function idRefTest():void + { + var xml:XML = + + + 1 + + 1 + + ; + var initial:Data = new Data(); + initial.node = new Node(); + initial.node.id = "1"; + initial.referenceAtt = initial.node; + initial.referenceElement = initial.node; + initial.referenceArray = new ArrayCollection([initial.node]); + var xmlInitial:XML = FxBEngine.instance.getXmlSerializer().serialize(initial) as XML; + assertEquals("Node id missing", "1", String(xmlInitial.node.@id)); + assertEquals("Reference att id missing", "1", String(xmlInitial.referenceAtt.@id)); + assertEquals("Reference element id missing", "1", String(xmlInitial.referenceElement)); + assertEquals("Reference Array missing", "1", String(xmlInitial.referenceArray[0].node)); + var data:Data = FxBEngine.instance.getXmlSerializer().deserialize(xml, Data) + assertEquals("Node differs from attribute value", data.node, data.referenceAtt); + assertEquals("Node differs from element value", data.node, data.referenceElement); + assertEquals("Node differs from array's first item value", data.node, data.referenceArray.getItemAt(0)); + } + + [Test] + public function xsiTypeTest():void + { + var item:Main = new Main(); + item.property = new ItemA(); + item.id = 3; + item.property.element = "test"; + ItemA(item.property).fieldA = "valueA"; + item.list = [new ItemA(), new ItemB()]; + ItemA(item.list[0]).fieldA = "ouj"; + ItemB(item.list[1]).fieldB = "klm"; + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + engine.processTypes(ItemA, ItemB); + engine.configuration.getResponseTypeByXsiType = true; + var xml:XML = engine.serialize(item) as XML; + assertThat(xml.property[0].@[XmlUtils.xsiType], equalTo("ItemA")); + assertThat(xml.members.listItem[0].@[XmlUtils.xsiType], equalTo("ItemA")); + assertThat(xml.members.listItem[1].@[XmlUtils.xsiType], equalTo("ItemB")); + var copy:Main = engine.deserialize(xml, Main); + assertThat(copy.id, equalTo(item.id)); + assertThat(copy.property, instanceOf(ItemA)); + assertThat(copy.property.element, equalTo(item.property.element)); + assertThat(ItemA(copy.property).fieldA, equalTo(ItemA(item.property).fieldA)); + assertThat(copy.list[0], instanceOf(ItemA)); + assertThat(copy.list[1], instanceOf(ItemB)); + } + + [Test] + public function testSerializeXSITypeWithNS():void + { + var item:Main = new Main(); + item.id = 1; + item.property = new ItemA(); + item.property.element = "test"; + ItemA(item.property).fieldA = "valueA"; + var itemA:ItemA = new ItemA(); + itemA.element = "test a"; + ItemA(itemA).fieldA = "field a"; + var itemB:ItemB = new ItemB(); + itemB.element = "test b"; + ItemB(itemB).fieldB = "field b"; + item.list = [itemA, itemB]; + + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + engine.processTypes(BaseItem, ItemA, ItemB); + engine.configuration.getResponseTypeByXsiType = true; + + var xml:XML = engine.serialize(item, false, "xsiNS") as XML; + assertNotNull(xml); + + var a:Namespace = new Namespace("a", "http://test.com/xsiNS"); + assertThat(xml.a::property[0].@[XmlUtils.xsiType], equalTo("a:ItemA")); + assertThat(xml.a::members.a::listItem[0].@[XmlUtils.xsiType], equalTo("a:ItemA")); + assertThat(xml.a::members.a::listItem[1].@[XmlUtils.xsiType], equalTo("a:ItemB")); + + var copy:Main = engine.deserialize(xml, Main, false, "xsiNS"); + assertThat(copy.id, equalTo(item.id)); + assertThat(copy.property, instanceOf(ItemA)); + assertThat(copy.property.element, equalTo(item.property.element)); + assertThat(ItemA(copy.property).fieldA, equalTo(ItemA(item.property).fieldA)); + assertThat(copy.list[0], instanceOf(ItemA)); + assertThat(copy.list[1], instanceOf(ItemB)); + } + + [Test] + public function testDeserializeXSITypeWithNS():void + { + var xml:XML = + + test + + + + test a + + + test b + + + ; + + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + engine.processTypes(BaseItem, ItemA, ItemB); + engine.configuration.getResponseTypeByXsiType = true; + + var data:Main = engine.deserialize(xml, Main, false, "xsiNS"); + + assertEquals(1, data.id); + assertNotNull(data.property); + assertTrue(data.property is ItemA); + assertEquals("test", data.property.element); + assertEquals(2, data.list.length); + assertTrue(data.list[0] is ItemA); + assertEquals("test a", data.list[0].element); + } + + [Test] + public function checkError():void + { + var vo:TestVO = new TestVO(); + vo.intTest = new testVO6(); + testVO6(vo.intTest).test6Inst = "6test6"; + vo.intTest1 = new testVO7(); + testVO7(vo.intTest1).test7Inst = "7test7"; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(vo); + var copy:TestVO = FxBEngine.instance.getXmlSerializer().deserialize(xml, TestVO); + assertThat(copy.intTest, instanceOf(testVO6)); + assertThat(testVO6(vo.intTest).test6Inst, equalTo("6test6")); + assertThat(copy.intTest1, instanceOf(testVO7)); + assertThat(testVO7(vo.intTest1).test7Inst, equalTo("7test7")); + } + + [Test] + public function testArrayListSerialization():void + { + var obj:ArrayListItem = new ArrayListItem(); + obj.id = "4"; + obj.list = new ArrayList(["one", "three", "two"]); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(obj); + var copy:ArrayListItem = FxBEngine.instance.getXmlSerializer().deserialize(xml, ArrayListItem); + assertThat(copy.list, notNullValue()); + assertThat(copy.list.length, equalTo(3)); + assertThat(copy.list.getItemAt(0), equalTo(obj.list.getItemAt(0))); + assertThat(copy.list.getItemAt(1), equalTo(obj.list.getItemAt(1))); + assertThat(copy.list.getItemAt(2), equalTo(obj.list.getItemAt(2))); + } + + [Test] + public function testIgnoreMissingFields():void + { + var engine:IFlexXB = FxBEngine.instance.getXmlSerializer(); + engine.configuration.ignoreMissingContent = true; + var xml:XML = + 33 + ; + var copy:Mock3 = engine.deserialize(xml, Mock3); + assertThat(copy.id, equalTo(new Mock3().id)); + assertNotNull(copy.list); + assertThat(copy.list.length, equalTo(3)); + engine.configuration.ignoreMissingContent = false; + copy = engine.deserialize(xml, Mock3); + assertThat(copy.id, equalTo(0)); + assertNotNull(copy.list); + assertThat(copy.list.length, equalTo(0)); + } + + [Test] + public function testArrayMemberNamespace():void + { + var item:NamespacedArrayMember = new NamespacedArrayMember(); + item.listA = ["one", "two", "three"]; + item.listB = [1, 2]; + + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(item); + + var aliasNS:Namespace = new Namespace("ns", "www.example.com/ns"); + var memberNS:Namespace = new Namespace("member", "www.example.com/member"); + assertNotNull(xml.listA[0].memberNS::string[0]); + assertNotNull(xml.aliasNS::listB[0]); + assertNotNull(xml.aliasNS::listB[0].memberNS::int[0]); + + var copy:NamespacedArrayMember = FxBEngine.instance.getXmlSerializer().deserialize(xml, NamespacedArrayMember); + + assertThat(copy.listA.length, equalTo(3)); + assertThat(copy.listA[0], equalTo("one")); + assertThat(copy.listB.length, equalTo(2)); + assertThat(copy.listB[0], equalTo(1)); + } + + [Test] + public function testXsiNill():void + { + var item:NillableData = new NillableData(); + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(item); + assertThat(xml.nested.elementNillable.length(), equalTo(1)); + assertThat(xml.nested.elementNillable[0].children().length(), equalTo(0)); + assertThat(xml.nested.elementNillable[0].attribute(new QName("http://www.w3.org/2001/XMLSchema-instance", "nil")).toString(), equalTo('true')); + var copy:NillableData = FxBEngine.instance.getXmlSerializer().deserialize(xml, NillableData); + assertNull(copy.elementNillable); + } + + [Test] + public function testDerivedType():void + { + var x:X = new X(); + x.a = new B(); + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + var xml:XML = engine.serialize(x) as XML; + var newX:X = engine.deserialize(xml, X) as X; + assertThat(newX.a, notNullValue()); + assertThat(newX.a, instanceOf(B)) + + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/XmlSpecialCharEscapeTest.as b/testSrc/com/googlecode/flexxb/XmlSpecialCharEscapeTest.as new file mode 100644 index 0000000..23be882 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/XmlSpecialCharEscapeTest.as @@ -0,0 +1,50 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.testData.NameOrdered; + + import org.flexunit.Assert; + + /** + * + * @author Alexutz + * + */ + public class XmlSpecialCharEscapeTest + { + + [Test] + public function testEscapeCharsOnElements():void + { + var target:NameOrdered = new NameOrdered(); + target.test2 = "EscapeChar OK"; + target.test3 = "EscapeChar2 OK"; + target.reference = ""; + target.list = ["Alt escape test ", "nik", "test4<", ""]; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + Assert.assertEquals("Escape Char element is wrong", "EscapeChar OK", (xml.test2[0] as XML).children()[0]); + Assert.assertEquals("Escape Char 2 element is wrong", "EscapeChar2 OK", xml.@test3); + Assert.assertEquals("Reference has wrong escape chars", "", (xml.reference[0] as XML).children()[0]); + Assert.assertEquals("Array member has wrong escape chars", "Alt escape test ", xml.list[0].testerElem[0].children()[0]); + Assert.assertEquals("Array member has wrong escape chars", "nik", xml.list[0].testerElem[1].children()[0]); + Assert.assertEquals("Array member has wrong escape chars", "test4<", xml.list[0].testerElem[2].children()[0]); + Assert.assertEquals("Array member has wrong escape chars", "", xml.list[0].testerElem[3].children()[0]); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/XmlTests.as b/testSrc/com/googlecode/flexxb/XmlTests.as new file mode 100644 index 0000000..7ba22e9 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/XmlTests.as @@ -0,0 +1,56 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb +{ + import com.googlecode.flexxb.annotation.DefaultValueTest; + import com.googlecode.flexxb.annotation.VersioningTest; + import com.googlecode.flexxb.annotation.XmlArrayTest; + import com.googlecode.flexxb.annotation.XmlAttributeTest; + import com.googlecode.flexxb.annotation.XmlClassTest; + import com.googlecode.flexxb.annotation.XmlElementTest; + import com.googlecode.flexxb.converter.ConverterTest; + + [Suite(description="Run the xml tests")] + [RunWith("org.flexunit.runners.Suite")] + public class XmlTests + { + + public var xmlClass:XmlClassTest; + + public var xmlAttribute:XmlAttributeTest; + + public var xmlElement:XmlElementTest; + + public var xmlArray:XmlArrayTest; + + public var xmlSerializer:XmlSerializerTest; + + public var elementOrder:XmlElementOrderTest; + + public var specialChars:XmlSpecialCharEscapeTest; + + public var defaultValue:DefaultValueTest; + + public var versioning:VersioningTest; + + public var namespaceTest:NamespaceTest; + + public var collisionDetectionTest:CircularReferenceTest; + + public var converter:ConverterTest; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/annotation/AnnotationTest.as b/testSrc/com/googlecode/flexxb/annotation/AnnotationTest.as new file mode 100644 index 0000000..1c5408f --- /dev/null +++ b/testSrc/com/googlecode/flexxb/annotation/AnnotationTest.as @@ -0,0 +1,122 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation +{ + import avmplus.RMember; + import avmplus.R; + import avmplus.RObject; + + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.testData.Mock; + + import flash.utils.describeType; + + import org.flexunit.Assert; + + /** + * + * @author Alexutz + * + */ + public class AnnotationTest + { + + protected function getTestObject():Object + { + return new Mock(); + } + + /** + * Method that handles annotation validation. It tests the annotation against a + * value list received as a list of parameters. The list is as follows: + *

    + *
  • - Field Name
  • + *
  • - Field Type
  • + *
  • - Name (as given in the objects' annotation)
  • + *
  • - Custom parameters handles in overrides of the customValidate method
  • + *
+ * @param annotation annotation to be validated + * @param args values List + * + */ + protected final function validate(annotation:Annotation, ...args):void + { + Assert.assertNotNull("Null annotation", annotation); + Assert.assertNotNull("Validation arguments are missing", args); + Assert.assertNotNull("Null name", annotation.name); + Assert.assertEquals("Field Name is incorrect", args[0], annotation.name.localName); + Assert.assertEquals("Field Type is incorrect", args[1], annotation.type); + Assert.assertEquals("Alias is incorrect", args[2], annotation.alias); + customValidate.apply(this, [annotation].concat(args)); + } + + /** + * + * @param annotation + * @param args + * + */ + protected function customValidate(annotation:Annotation, ...args):void + { + } + + /** + * + * @param descriptor + * + */ + protected function runTest(descriptor:RObject):void + { + } + + /** + * + * @param fieldName + * @param descriptor + * @return + * + */ + protected final function getFieldDescriptor(fieldName:String, descriptor:RObject):RMember + { + var m:RMember; + for each (m in descriptor.traits.variables) + { + if(m.name == fieldName) + { + return m; + } + } + + for each (m in descriptor.traits.accessors) + { + if(m.name == fieldName) + { + return m; + } + } + + return null; + } + + [Test] + public function testAnnotation():void + { + var descriptor:RObject = R.describeFromXML(describeType(getTestObject()), R.VARIABLES | R.TRAITS | R.METADATA | R.METHODS | R.ACCESSORS | R.BASES | R.CONSTRUCTOR); + runTest(descriptor); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/annotation/DefaultValueTest.as b/testSrc/com/googlecode/flexxb/annotation/DefaultValueTest.as new file mode 100644 index 0000000..b01efdb --- /dev/null +++ b/testSrc/com/googlecode/flexxb/annotation/DefaultValueTest.as @@ -0,0 +1,40 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.testData.DefaultValueTestObj; + + import org.flexunit.Assert; + + public class DefaultValueTest + { + [Test] + public function testDefaultValue():void + { + var v:DefaultValueTestObj; + var xml:XML = + + 3 + ; + v = FxBEngine.instance.getXmlSerializer().deserialize(xml, DefaultValueTestObj); + Assert.assertEquals("String field wrong", "MyValue", v.string); + Assert.assertEquals("min field wrong", 3, v.min); + Assert.assertEquals("max field wrong", 5, v.max); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/annotation/VersioningTest.as b/testSrc/com/googlecode/flexxb/annotation/VersioningTest.as new file mode 100644 index 0000000..04af9ce --- /dev/null +++ b/testSrc/com/googlecode/flexxb/annotation/VersioningTest.as @@ -0,0 +1,80 @@ +package com.googlecode.flexxb.annotation +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.core.IFlexXB; + import com.googlecode.flexxb.core.XmlVersionExtractor; + import com.googlecode.testData.Mock; + import com.googlecode.testData.Mock2; + import com.googlecode.testData.VersionedItem; + + import org.flexunit.assertThat; + import org.flexunit.asserts.assertNotNull; + import org.flexunit.asserts.assertNull; + import org.hamcrest.object.equalTo; + + public final class VersioningTest + { + [Test] + public function testMultipleVersions():void + { + var item:VersionedItem = new VersionedItem(); + item.id = "MyId"; + item.name = "MyName"; + item.value = new Mock(); + item.value.aField = "field1"; + item.mock2 = new Mock2(); + item.mock2.id = 12345; + + var v1Ns:Namespace = new Namespace("http://www.me.com/me/de"); + + var xmlV1:XML = FxBEngine.instance.getXmlSerializer().serialize(item) as XML; + + assertThat(xmlV1.name().toString(), equalTo(new QName(v1Ns, "item").toString())); + assertThat(xmlV1.inScopeNamespaces().length, equalTo(1)); + assertThat(xmlV1.namespace().uri, equalTo("http://www.me.com/me/de")); + assertThat(xmlV1.@v1Ns::id, equalTo("MyId")); + assertThat(xmlV1.@v1Ns::pName, equalTo("MyName")); + assertThat(xmlV1.child(new QName(v1Ns, "mock")).length(), equalTo(0)); + + var xmlV2:XML = FxBEngine.instance.getXmlSerializer().serialize(item, false, "v2") as XML; + + assertThat(xmlV2.name().toString(), equalTo("VersionedItem")); + assertThat(xmlV2.namespace().uri, equalTo("")); + assertThat(xmlV2.id, equalTo("MyId")); + assertThat(xmlV2.@itemName, equalTo("MyName")); + assertThat(xmlV2.child("mock").length(), equalTo(1)); + + var cloneV1:VersionedItem = FxBEngine.instance.getXmlSerializer().deserialize(xmlV1, VersionedItem, false); + assertThat(item.id, equalTo(cloneV1.id)); + assertThat(item.name, equalTo(cloneV1.name)); + assertNull(cloneV1.value); + assertNotNull(cloneV1.mock2); + + var cloneV2:VersionedItem = FxBEngine.instance.getXmlSerializer().deserialize(xmlV2, VersionedItem, false, "v2"); + assertThat(item.id, equalTo(cloneV2.id)); + assertThat(item.name, equalTo(cloneV2.name)); + assertNotNull(cloneV2.value); + assertNull(cloneV2.mock2); + } + + [Test] + public function autoVersionDetectionTest():void + { + var v2Xml:XML = + MyId + + YES + + ; + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + engine.configuration.versionExtractor = new XmlVersionExtractor(); + var item:VersionedItem = engine.deserialize(v2Xml, VersionedItem); + assertThat(item.id, equalTo("MyId")); + assertThat(item.name, equalTo("MyName")); + assertNull(item.mock2); + assertNotNull(item.value); + assertThat(item.value.readOnly, equalTo("YES")); + assertThat(item.value.version, equalTo(6)); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/annotation/XmlArrayTest.as b/testSrc/com/googlecode/flexxb/annotation/XmlArrayTest.as new file mode 100644 index 0000000..6cff8e8 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/annotation/XmlArrayTest.as @@ -0,0 +1,87 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation +{ + import avmplus.R; + import avmplus.RObject; + + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.parser.MetaParser; + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlAttribute; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlNamespace; + import com.googlecode.flexxb.serializer.XmlArraySerializer; + import com.googlecode.flexxb.serializer.XmlAttributeSerializer; + import com.googlecode.flexxb.serializer.XmlClassSerializer; + import com.googlecode.flexxb.serializer.XmlElementSerializer; + import com.googlecode.testData.Mock; + import com.googlecode.testData.VectoredElement; + + import flash.utils.describeType; + + import org.flexunit.Assert; + import org.flexunit.assertThat; + import org.hamcrest.object.equalTo; + + public class XmlArrayTest extends AnnotationTest + { + + protected override function runTest(descriptor:RObject):void + { + var parser:MetaParser = new MetaParser(factory); + var att1:XmlArray = new XmlArray(parser.parseField(getFieldDescriptor("result", descriptor))[0]); + validate(att1, "result", Array, "data", null, false, Mock); + } + + protected override function customValidate(annotation:Annotation, ...args):void + { + Assert.assertEquals("IgnoreOn is incorrect", args[3], XmlArray(annotation).ignoreOn); + Assert.assertEquals("SerializePartialElement is incorrect", args[4], XmlArray(annotation).serializePartialElement); + Assert.assertEquals("Type is incorrect", args[5], XmlArray(annotation).memberType); + } + + private var factory:AnnotationFactory; + + [Before] + public function before():void + { + factory = FxBEngine.instance.getXmlSerializer().factory; + + factory.registerAnnotation(XmlAttribute.ANNOTATION_NAME, XmlAttribute, XmlAttributeSerializer, null); + factory.registerAnnotation(XmlElement.ANNOTATION_NAME, XmlElement, XmlElementSerializer, null); + factory.registerAnnotation(XmlArray.ANNOTATION_NAME, XmlArray, XmlArraySerializer, null); + factory.registerAnnotation(XmlClass.ANNOTATION_NAME, XmlClass, XmlClassSerializer, null); + factory.registerAnnotation(XmlConstants.ANNOTATION_NAMESPACE, XmlNamespace, null, null); + } + + [Test] + public function validateVectorSupport():void + { + var parser:MetaParser = new MetaParser(factory); + var descriptor:XML = describeType(VectoredElement); + var xml:RObject = R.describeFromXML(descriptor, R.VARIABLES | R.TRAITS | R.METADATA | R.METHODS | R.ACCESSORS | R.BASES | R.CONSTRUCTOR); + var att1:XmlArray = new XmlArray(parser.parseField(xml.traits.variables[0])[0]); + assertThat(att1.type, equalTo(Vector.)); + assertThat(att1.memberType, equalTo(String)); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/annotation/XmlAttributeTest.as b/testSrc/com/googlecode/flexxb/annotation/XmlAttributeTest.as new file mode 100644 index 0000000..89fe2a0 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/annotation/XmlAttributeTest.as @@ -0,0 +1,71 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation +{ + import avmplus.RObject; + + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.Stage; + import com.googlecode.flexxb.annotation.parser.MetaParser; + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlAttribute; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlNamespace; + import com.googlecode.flexxb.serializer.XmlArraySerializer; + import com.googlecode.flexxb.serializer.XmlAttributeSerializer; + import com.googlecode.flexxb.serializer.XmlClassSerializer; + import com.googlecode.flexxb.serializer.XmlElementSerializer; + + import org.flexunit.Assert; + + public class XmlAttributeTest extends AnnotationTest + { + + protected override function runTest(descriptor:RObject):void + { + var parser:MetaParser = new MetaParser(factory); + var att1:XmlAttribute = new XmlAttribute(parser.parseField(getFieldDescriptor("aField", descriptor))[0]); + validate(att1, "aField", String, "stuff", null); + + var att2:XmlAttribute = new XmlAttribute(parser.parseField(getFieldDescriptor("date", descriptor))[0]); + validate(att2, "date", Date, "date", Stage.SERIALIZE); + } + + private var factory:AnnotationFactory; + + [Before] + public function before():void + { + factory = FxBEngine.instance.getXmlSerializer().factory; + + factory.registerAnnotation(XmlAttribute.ANNOTATION_NAME, XmlAttribute, XmlAttributeSerializer, null); + factory.registerAnnotation(XmlElement.ANNOTATION_NAME, XmlElement, XmlElementSerializer, null); + factory.registerAnnotation(XmlArray.ANNOTATION_NAME, XmlArray, XmlArraySerializer, null); + factory.registerAnnotation(XmlClass.ANNOTATION_NAME, XmlClass, XmlClassSerializer, null); + factory.registerAnnotation(XmlConstants.ANNOTATION_NAMESPACE, XmlNamespace, null, null); + } + + protected override function customValidate(annotation:Annotation, ...args):void + { + Assert.assertEquals("IgnoreOn is incorrect", args[3], XmlAttribute(annotation).ignoreOn); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/annotation/XmlClassTest.as b/testSrc/com/googlecode/flexxb/annotation/XmlClassTest.as new file mode 100644 index 0000000..c72a513 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/annotation/XmlClassTest.as @@ -0,0 +1,106 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation +{ + import avmplus.R; + import avmplus.RObject; + + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.Constants; + import com.googlecode.flexxb.annotation.contract.ConstructorArgument; + import com.googlecode.flexxb.annotation.parser.MetaParser; + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlAttribute; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlNamespace; + import com.googlecode.flexxb.serializer.XmlArraySerializer; + import com.googlecode.flexxb.serializer.XmlAttributeSerializer; + import com.googlecode.flexxb.serializer.XmlClassSerializer; + import com.googlecode.flexxb.serializer.XmlElementSerializer; + import com.googlecode.testData.ConstructorRefObj; + import com.googlecode.testData.Mock; + + import flash.utils.describeType; + + import org.flexunit.Assert; + + public class XmlClassTest extends AnnotationTest + { + + [Test] + public function testConstructorParameters():void + { + var target:ConstructorRefObj = new ConstructorRefObj("test", 1, true); + FxBEngine.instance.getXmlSerializer().serialize(null); + var parser:MetaParser = new MetaParser(factory); + var descriptor:XML = describeType(ConstructorRefObj); + var json:RObject = R.describeFromXML(descriptor, R.VARIABLES | R.TRAITS | R.METADATA | R.METHODS | R.ACCESSORS | R.BASES | R.CONSTRUCTOR); + var cls:XmlClass = parser.parseDescriptor(json)[0]; + Assert.assertFalse("Class constructor should not be default", cls.constructor.isDefault); + Assert.assertNotNull("ParameterFields is Null", cls.constructor.parameterFields); + Assert.assertEquals("There are more or less than 3 parameters", 3, cls.constructor.parameterFields.length); + } + + private var factory:AnnotationFactory; + + [Before] + public function before():void + { + factory = FxBEngine.instance.getXmlSerializer().factory; + factory.registerAnnotation(ConstructorArgument.ANNOTATION_CONSTRUCTOR_ARGUMENT, ConstructorArgument, null, null); + factory.registerAnnotation(XmlAttribute.ANNOTATION_NAME, XmlAttribute, XmlAttributeSerializer, null); + factory.registerAnnotation(XmlElement.ANNOTATION_NAME, XmlElement, XmlElementSerializer, null); + factory.registerAnnotation(XmlArray.ANNOTATION_NAME, XmlArray, XmlArraySerializer, null); + factory.registerAnnotation(XmlClass.ANNOTATION_NAME, XmlClass, XmlClassSerializer, null); + factory.registerAnnotation(XmlConstants.ANNOTATION_NAMESPACE, XmlNamespace, null, null); + } + + protected override function runTest(descriptor:RObject):void + { + var parser:MetaParser = new MetaParser(factory); + var clss:Array = parser.parseDescriptor(descriptor); + var a:XmlClass = clss[0]; + if (a.version == "v2") + { + validate(a, "Mock", Mock, "V2", "ulala", "www.me.com"); + } + else + { + validate(a, "Mock", Mock, "MyClass", "test", "http://www.test.com/xmlns/pp/v1"); + } + a = clss[1]; + if (a.version == "v2") + { + validate(a, "Mock", Mock, "V2", "ulala", "www.me.com"); + } + else + { + validate(a, "Mock", Mock, "MyClass", "test", "http://www.test.com/xmlns/pp/v1"); + } + } + + protected override function customValidate(annotation:Annotation, ...args):void + { + Assert.assertEquals("Namespace prefix is incorrect", args[3], annotation.nameSpace.prefix); + Assert.assertEquals("Namespace uri is incorrect", args[4], annotation.nameSpace.uri); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/annotation/XmlElementTest.as b/testSrc/com/googlecode/flexxb/annotation/XmlElementTest.as new file mode 100644 index 0000000..7cfd50b --- /dev/null +++ b/testSrc/com/googlecode/flexxb/annotation/XmlElementTest.as @@ -0,0 +1,83 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.annotation +{ + import avmplus.RObject; + + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.parser.MetaParser; + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.annotation.contract.Annotation; + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlAttribute; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlNamespace; + import com.googlecode.flexxb.serializer.XmlArraySerializer; + import com.googlecode.flexxb.serializer.XmlAttributeSerializer; + import com.googlecode.flexxb.serializer.XmlClassSerializer; + import com.googlecode.flexxb.serializer.XmlElementSerializer; + import com.googlecode.testData.Mock3; + + import org.flexunit.Assert; + + public class XmlElementTest extends AnnotationTest + { + + protected override function runTest(descriptor:RObject):void + { + var parser:MetaParser = new MetaParser(factory); + var att1:XmlElement = new XmlElement(parser.parseField(getFieldDescriptor("version", descriptor))[0]); + validate(att1, "version", int, "objVersion", null, false); + + var att2:XmlElement = new XmlElement(parser.parseField(getFieldDescriptor("reference", descriptor))[0]); + validate(att2, "reference", Object, "reference", null, true); + + var att3:XmlElement = new XmlElement(parser.parseField(getFieldDescriptor("link", descriptor))[0]); + validate(att3, "link", Mock3, "mock3", null, true); + } + + private var factory:AnnotationFactory; + + [Before] + public function before():void + { + factory = FxBEngine.instance.getXmlSerializer().factory; + + factory.registerAnnotation(XmlAttribute.ANNOTATION_NAME, XmlAttribute, XmlAttributeSerializer, null); + factory.registerAnnotation(XmlElement.ANNOTATION_NAME, XmlElement, XmlElementSerializer, null); + factory.registerAnnotation(XmlArray.ANNOTATION_NAME, XmlArray, XmlArraySerializer, null); + factory.registerAnnotation(XmlClass.ANNOTATION_NAME, XmlClass, XmlClassSerializer, null); + factory.registerAnnotation(XmlConstants.ANNOTATION_NAMESPACE, XmlNamespace, null, null); + } + + /** + * Custom validation. Handles the fourth and fifth parameters: + * - IgnoreOn + * - SerializePartialElement + * @param annotation + * @param args + * + */ + protected override function customValidate(annotation:Annotation, ...args):void + { + Assert.assertEquals("IgnoreOn is incorrect", args[3], XmlElement(annotation).ignoreOn); + Assert.assertEquals("SerializePartialElement is incorrect", args[4], XmlElement(annotation).serializePartialElement); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/api/ApiTests.as b/testSrc/com/googlecode/flexxb/api/ApiTests.as new file mode 100644 index 0000000..d9902e3 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/api/ApiTests.as @@ -0,0 +1,35 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.xml.api.FxApiComponentTest; + + /** + * + * @author Alexutz + * + */ + [Suite] + [RunWith("org.flexunit.runners.Suite")] + public class ApiTests + { + + public var apiComponent:FxApiComponentTest; + + public var customClass:CustomClassTest; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/api/CustomClassTest.as b/testSrc/com/googlecode/flexxb/api/CustomClassTest.as new file mode 100644 index 0000000..b3f14c5 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/api/CustomClassTest.as @@ -0,0 +1,59 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import com.googlecode.flexxb.core.FxBEngine; + + public class CustomClassTest + { + + [Test] + public function testPanelSerialization():void + { + var xml:XML = + + + + + + + + + + + + + + + ; + var engine:FxBEngine = new FxBEngine(); + engine.api.processDescriptorsFromXml(xml); + var pipe:PipeLine = new PipeLine(); + pipe.name = "test"; + pipe.panels = []; + var panel:FetchPanel = new FetchPanel(); + panel.x = 2; + panel.y = 2; + pipe.panels.push(panel); + panel = new FetchPanel(); + panel.x = 2; + panel.y = 2; + pipe.panels.push(panel); + xml = engine.getXmlSerializer().serialize(pipe) as XML; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/api/FetchPanel.as b/testSrc/com/googlecode/flexxb/api/FetchPanel.as new file mode 100644 index 0000000..18a2cc3 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/api/FetchPanel.as @@ -0,0 +1,28 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + import mx.containers.Panel; + + public class FetchPanel extends Panel + { + public function FetchPanel() + { + super(); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/api/PipeLine.as b/testSrc/com/googlecode/flexxb/api/PipeLine.as new file mode 100644 index 0000000..a5d9b59 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/api/PipeLine.as @@ -0,0 +1,31 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.api +{ + public class PipeLine + { + [XmlAttribute] + public var name:String; + [XmlArray] + [ArrayElementType("com.googlecode.flexxb.api.FetchPanel")] + public var panels:Array; + + public function PipeLine() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/cache/CacheTest.as b/testSrc/com/googlecode/flexxb/cache/CacheTest.as new file mode 100644 index 0000000..eb831ae --- /dev/null +++ b/testSrc/com/googlecode/flexxb/cache/CacheTest.as @@ -0,0 +1,116 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.cache +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.core.IFlexXB; + import com.googlecode.testData.Mock; + import com.googlecode.testData.Mock3; + import com.googlecode.testData.Mock4; + + import flash.events.Event; + + import flexunit.framework.Assert; + + import org.flexunit.assertThat; + import org.hamcrest.core.not; + import org.hamcrest.object.equalTo; + + public class CacheTest + { + + private static var objectCache:ObjectCache; + private static var objectPool:ObjectPool; + private static var engine:IFlexXB; + + [BeforeClass] + public static function initialize():void + { + objectCache = new ObjectCache(); + objectPool = new ObjectPool(); + engine = new FxBEngine().getXmlSerializer(); + } + + [Test(order="1")] + public function objectCache_testEmptyCache():void + { + objectCache.putObject("id", new Mock()); + Assert.assertTrue("Cache does not contain the object", objectCache.isInCache("id", Mock)); + objectCache.clearCache(Mock); + Assert.assertNull(objectCache.getFromCache("id", Mock)); + } + + [Test(order="2")] + public function objectCache_testCache():void + { + var obj:Mock3 = new Mock3(); + obj.id = 352; + obj.attribute = true; + engine.configuration.setCacheProvider(objectCache); + var xml:XML = engine.serialize(obj) as XML; + var copy:Mock3 = engine.deserialize(xml, Mock3); + Assert.assertEquals(copy.id, obj.id); + Assert.assertTrue("Deserialized object not cached", objectCache.isInCache(String(copy.id), Mock3)); + Assert.assertEquals("Different instances", copy, objectCache.getFromCache(String(copy.id), Mock3)); + } + + [Test(description="This test covers the object pool functionality. It will test that objects that get released use are then reused when need arises and when all available objects are used, it will create new instances to accomodate needs.")] + public function testObjectPool():void + { + var obj1:Object = objectPool.getNewInstance(Object, null); + var obj2:Object = objectPool.getNewInstance(Object, null); + var obj3:Object = objectPool.getNewInstance(Object, null); + var temp:Object; + assertThat("Object instances are equal", obj1, not(equalTo(obj2))); + assertThat("Object instances are equal", obj2, not(equalTo(obj3))); + assertThat("Object instances are equal", obj3, not(equalTo(obj1))); + objectPool.releaseInstance(obj2); + temp = objectPool.getFromCache(null, Object); + assertThat("Object is not propely released", temp, equalTo(obj2)); + objectPool.clearCache(); + temp = objectPool.getNewInstance(Object, null); + assertThat("Cleanup not working", temp, not(equalTo(obj1))); + assertThat("Cleanup not working", temp, not(equalTo(obj2))); + assertThat("Cleanup not working", temp, not(equalTo(obj3))); + } + + [Test(description="This test covers the call of the clear method on IPooledObject implementors when they get released")] + public function objectClearenceOnRelease():void + { + clearFlag = false; + var obj:Mock4 = objectPool.getNewInstance(Mock4, null); + obj.addEventListener(Mock4.CLEAR, onClearCalled); + objectPool.releaseInstance(obj); + obj.removeEventListener(Mock4.CLEAR, onClearCalled); + assertThat("Clear method not called on object", true, equalTo(clearFlag)); + } + + private var clearFlag:Boolean; + + private function onClearCalled(event:Event):void + { + clearFlag = true; + } + + [AfterClass] + public static function cleanup():void + { + objectCache = null; + objectPool = null; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/converter/ConverterTest.as b/testSrc/com/googlecode/flexxb/converter/ConverterTest.as new file mode 100644 index 0000000..e791f03 --- /dev/null +++ b/testSrc/com/googlecode/flexxb/converter/ConverterTest.as @@ -0,0 +1,28 @@ +package com.googlecode.flexxb.converter +{ + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.core.IFlexXB; + import com.googlecode.testData.ManyDates; + + import org.flexunit.assertThat; + import org.hamcrest.object.equalTo; + + public class ConverterTest + { + public function ConverterTest() + { + } + + [Test] + public function testArrayElementsConversion():void + { + var engine:IFlexXB = new FxBEngine().getXmlSerializer(); + engine.context.registerSimpleTypeConverter(new W3CDateConverter(), true); + var data:ManyDates = new ManyDates(); + data.dates = [new Date(2000, 1, 1, 12, 12, 12, 12), new Date(2012, 12, 21, 21, 12, 21, 12)]; + var xml:XML = engine.serialize(data) as XML; + assertThat(xml.dates.dateItem[0].text(), equalTo(new W3CDateConverter().toString(data.dates[0]))); + assertThat(xml.dates.dateItem[1].text(), equalTo(new W3CDateConverter().toString(data.dates[1]))); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/flexxb/xml/api/FxApiComponentTest.as b/testSrc/com/googlecode/flexxb/xml/api/FxApiComponentTest.as new file mode 100644 index 0000000..e2de7cc --- /dev/null +++ b/testSrc/com/googlecode/flexxb/xml/api/FxApiComponentTest.as @@ -0,0 +1,349 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.flexxb.xml.api +{ + import avmplus.RMember; + import avmplus.R; + import avmplus.RObject; + + import com.googlecode.flexxb.annotation.contract.AnnotationFactory; + import com.googlecode.flexxb.annotation.contract.AccessorType; + import com.googlecode.flexxb.annotation.contract.Constants; + import com.googlecode.flexxb.annotation.contract.ConstructorArgument; + import com.googlecode.flexxb.annotation.contract.Stage; + import com.googlecode.flexxb.annotation.parser.MetaParser; + import com.googlecode.flexxb.api.FxApiWrapper; + import com.googlecode.flexxb.api.XmlApiArray; + import com.googlecode.flexxb.api.XmlApiAttribute; + import com.googlecode.flexxb.api.XmlApiClass; + import com.googlecode.flexxb.api.XmlApiElement; + import com.googlecode.flexxb.api.XmlApiMember; + import com.googlecode.flexxb.api.flexxb_api_internal; + import com.googlecode.flexxb.converter.W3CDateConverter; + import com.googlecode.flexxb.core.FxBEngine; + import com.googlecode.flexxb.annotation.contract.XmlArray; + import com.googlecode.flexxb.annotation.contract.XmlAttribute; + import com.googlecode.flexxb.annotation.contract.XmlClass; + import com.googlecode.flexxb.annotation.contract.XmlConstants; + import com.googlecode.flexxb.annotation.contract.XmlElement; + import com.googlecode.flexxb.annotation.contract.XmlMember; + import com.googlecode.flexxb.annotation.contract.XmlNamespace; + import com.googlecode.flexxb.serializer.XmlArraySerializer; + import com.googlecode.flexxb.serializer.XmlAttributeSerializer; + import com.googlecode.flexxb.serializer.XmlClassSerializer; + import com.googlecode.flexxb.serializer.XmlElementSerializer; + import com.googlecode.testData.APITestObject; + import com.googlecode.testData.Address; + import com.googlecode.testData.Mock; + import com.googlecode.testData.Person; + import com.googlecode.testData.PhoneNumber; + + import flash.utils.Dictionary; + + import mx.collections.ArrayCollection; + + import org.flexunit.Assert; + + /** + * + * @author Alexutz + * + */ + public class FxApiComponentTest + { + + private var factory:AnnotationFactory; + + public function FxApiComponentTest() + { + new PhoneNumber(); + new Person(); + new Address(); + FxBEngine.instance.api.processTypeDescriptor(null); + factory = FxBEngine.instance.getXmlSerializer().factory; + factory.registerAnnotation(ConstructorArgument.ANNOTATION_CONSTRUCTOR_ARGUMENT, ConstructorArgument, null, null); + factory.registerAnnotation(XmlAttribute.ANNOTATION_NAME, XmlAttribute, XmlAttributeSerializer, null); + factory.registerAnnotation(XmlElement.ANNOTATION_NAME, XmlElement, XmlElementSerializer, null); + factory.registerAnnotation(XmlArray.ANNOTATION_NAME, XmlArray, XmlArraySerializer, null); + factory.registerAnnotation(XmlClass.ANNOTATION_NAME, XmlClass, XmlClassSerializer, null); + factory.registerAnnotation(XmlConstants.ANNOTATION_NAMESPACE, XmlNamespace, null, null); + } + + [Test] + public function testFxAttribute():void + { + var api:XmlApiAttribute = XmlApiAttribute.create("testAtt", String, null, 'aliasAttTest'); + var descriptor:RMember = FxBEngine.instance.api.buildFieldDescriptor(api); + var att:XmlAttribute = new XmlAttribute(new MetaParser(factory).parseField(descriptor)[0]); + doMemberAssertion(api, att); + } + + [Test] + public function testFxElement():void + { + var api:XmlApiElement = XmlApiElement.create("testAtt", String, null, 'aliasAttTest'); + var descriptor:RMember = FxBEngine.instance.api.buildFieldDescriptor(api); + var att:XmlElement = new XmlElement(new MetaParser(factory).parseField(descriptor)[0]); + doElementAssertion(api, att); + } + + [Test] + public function testFxArray():void + { + var api:XmlApiArray = XmlApiArray.create("testAtt", String, null, 'aliasAttTest'); + var descriptor:RMember = FxBEngine.instance.api.buildFieldDescriptor(api); + var att:XmlArray = new XmlArray(new MetaParser(factory).parseField(descriptor)[0]); + doArrayAssertion(api, att); + } + + [Test] + public function testFxClass():void + { + var parser:MetaParser = new MetaParser(factory); + var cls:XmlApiClass = buildDescriptor(); + var descriptor:RObject = FxBEngine.instance.api.buildTypeDescriptor(cls); + var xmlCls:XmlClass = parser.parseDescriptor(descriptor)[0]; + Assert.assertEquals("wrong type", cls.type, xmlCls.type); + Assert.assertEquals("wrong alias", cls.alias, xmlCls.alias); + Assert.assertEquals("wrong prefix", cls.prefix, xmlCls.nameSpace.prefix); + Assert.assertEquals("wrong uri", cls.uri, xmlCls.nameSpace.uri); + Assert.assertEquals("wrong member count", 4, xmlCls.members.length); + Assert.assertEquals("wrong constructor argument count", 2, xmlCls.constructor.parameterFields.length); + } + + private function buildDescriptor():XmlApiClass + { + var cls:XmlApiClass = new XmlApiClass(Person, "APerson"); + cls.prefix = "test"; + cls.uri = "http://www.axway.com/xmlns/passport/v1"; + cls.addAttribute("firstName", String, null, "FirstName"); + cls.addAttribute("lastName", String, null, "LastName"); + cls.addElement("birthDate", Date, null, "BirthDate"); + cls.addElement("age", Number, null, "Age").ignoreOn = Stage.SERIALIZE; + cls.addArgument("firstName"); + cls.addArgument("lastName"); + return cls; + } + + [Test] + public function testSerializationWithApiDescriptor():void + { + var cls:XmlApiClass = buildDescriptor(); + FxBEngine.instance.api.processTypeDescriptor(cls); + var person:Person = new Person(); + person.firstName = "John"; + person.lastName = "Doe"; + person.birthDate = new Date(); + person.age = 34; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(person) as XML; + var copy:Person = FxBEngine.instance.getXmlSerializer().deserialize(xml, Person); + Assert.assertEquals("Wrong firstName", person.firstName, copy.firstName); + Assert.assertEquals("Wrong lastName", person.lastName, copy.lastName); + Assert.assertEquals("Wrong birthDate", person.birthDate.toString(), copy.birthDate.toString()); + Assert.assertEquals("Wrong age", 0, copy.age); + } + + [Test] + public function testFileDescriptorProcessing():void + { + var xml:XML = getXmlDescriptor(); + FxBEngine.instance.api; + var wrapper:FxApiWrapper = FxBEngine.instance.getXmlSerializer().deserialize(xml, FxApiWrapper); + Assert.assertEquals("Wrong number of classes parsed", 3, wrapper.descriptors.length); + Assert.assertEquals("Wrong version", 1, wrapper.version); + Assert.assertEquals("Wrong member count for first class", 4, XmlApiClass(wrapper.descriptors[0]).members.length); + Assert.assertEquals("Wrong constructor argument count for second class", 2, XmlApiClass(wrapper.descriptors[1]).constructorArguments.length); + } + + private function doArrayAssertion(apiMember:XmlApiArray, xmlArray:XmlArray):void + { + doElementAssertion(apiMember, xmlArray); + Assert.assertEquals("Wrong memberName", apiMember.memberName, xmlArray.memberName); + Assert.assertEquals("Wrong memberType", apiMember.memberType, xmlArray.memberType); + } + + private function doElementAssertion(apiMember:XmlApiElement, xmlElement:XmlElement):void + { + doMemberAssertion(apiMember, xmlElement); + Assert.assertEquals("Wrong getFromCache", apiMember.getFromCache, xmlElement.getFromCache); + Assert.assertEquals("Wrong serializePartialElement", apiMember.serializePartialElement, xmlElement.serializePartialElement); + Assert.assertEquals("Wrong nillable", apiMember.nillable, xmlElement.nillable); + } + + private function doMemberAssertion(apiMember:XmlApiMember, xmlMember:XmlMember):void + { + Assert.assertEquals("Wrong field name", apiMember.fieldName, xmlMember.name); + Assert.assertEquals("Wrong field type", apiMember.fieldType, xmlMember.type); + Assert.assertEquals("Field access type is wrong for writeOnly", apiMember.fieldAccessType == AccessorType.WRITE_ONLY, xmlMember.writeOnly); + Assert.assertEquals("Field access type is wrong for readOnly", apiMember.fieldAccessType == AccessorType.READ_ONLY, xmlMember.readOnly); + Assert.assertEquals("Wrong ignoreOn", apiMember.ignoreOn, xmlMember.ignoreOn); + Assert.assertEquals("Wrong alias", apiMember.alias, xmlMember.alias); + Assert.assertEquals("Wrong required", apiMember.isRequired, xmlMember.isRequired); + } + + [Test] + public function testMultipleNamespace():void + { + FxBEngine.instance.api; + var cls:XmlApiClass = new XmlApiClass(Mock); + var member:XmlApiMember = cls.addAttribute("version", Number, null, "Version"); + member.setNamespace(new Namespace("me", "www.me.com")); + member = cls.addElement("tester", String); + member.setNamespace(new Namespace("us", "www.us.com")); + member = cls.addAttribute("uue", String); + member = cls.addAttribute("uueedr", String); + member.setNamespace(new Namespace("me", "www.me.com")); + Assert.assertEquals("Wrong number of registered namespaces upon programatic build", 2, count(cls.flexxb_api_internal::namespaces)); + var xml:XML = getXmlDescriptor(); + var wrapper:FxApiWrapper = FxBEngine.instance.getXmlSerializer().deserialize(xml, FxApiWrapper); + Assert.assertEquals("Wrong number of registered namespaces upon deserialization", 2, count(XmlApiClass(wrapper.descriptors[0]).flexxb_api_internal::namespaces)); + } + + [Test] + public function testFullAPIProcessing():void + { + FxBEngine.instance.getXmlSerializer().context.registerSimpleTypeConverter(new W3CDateConverter()); + var cls:XmlApiClass = new XmlApiClass(APITestObject, "ATO"); + cls.prefix = "apitest"; + cls.uri = "http://www.apitest.com/api/test"; + cls.addAttribute("id", Number); + cls.addArgument("id", false); + var member:XmlApiMember = cls.addAttribute("name", String, AccessorType.READ_WRITE, "meta/objName"); + member.setNamespace(new Namespace("pref1", "http://www.p.r.com")); + cls.addElement("version", Number, null, "meta/objVersion"); + member = cls.addElement("currentDate", Date, null, "todayIs"); + member.setNamespace(new Namespace("pref1", "http://www.p.r.com")); + member = cls.addElement("xmlData", XML, null, "data"); + member.setNamespace(new Namespace("pref2", "http://www.p3.r2.com")); + cls.addAttribute("xmlAtts", XML, null, "attributes"); + var array:XmlApiArray = cls.addArray("results", ArrayCollection, null, "Results"); + array.memberName = "resultItem"; + array.memberType = String; + FxBEngine.instance.api.processTypeDescriptor(cls); + var target:APITestObject = new APITestObject(1234); + target.currentDate = new Date(); + target.name = "MyName"; + target.results = new ArrayCollection(["me", "you", "us"]); + target.version = 3; + target.xmlAtts = + + + + ; + target.xmlData = + + ; + var xml:XML = FxBEngine.instance.getXmlSerializer().serialize(target) as XML; + var copy:APITestObject = FxBEngine.instance.getXmlSerializer().deserialize(xml, APITestObject); + + Assert.assertEquals("Id is wrong", target.id, copy.id); + Assert.assertEquals("Name is wrong", target.name, copy.name); + Assert.assertEquals("Version is wrong", target.version, copy.version); + Assert.assertEquals("XmlAtts is wrong", target.xmlAtts.toXMLString(), copy.xmlAtts.toXMLString()); + Assert.assertEquals("XmlData is wrong", target.xmlData.toXMLString(), copy.xmlData.toXMLString()); + Assert.assertEquals("Results count is wrong", target.results.length, copy.results.length); + for (var i:int = 0; i < target.results.length; i++) + { + Assert.assertEquals("Results memeber indexed " + i + " is wrong", target.results[i], copy.results[i]); + } + Assert.assertEquals("Current date is wrong", target.currentDate.time, copy.currentDate.time); + } + + private function count(map:Dictionary):int + { + var size:int = 0; + for (var key:* in map) + { + size++; + } + return size; + } + + private function getXmlDescriptor():XML + { + var xml:XML = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ; + return xml; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/APITestObject.as b/testSrc/com/googlecode/testData/APITestObject.as new file mode 100644 index 0000000..24592d0 --- /dev/null +++ b/testSrc/com/googlecode/testData/APITestObject.as @@ -0,0 +1,42 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + import mx.collections.ArrayCollection; + + public class APITestObject + { + public var id:Number; + + public var name:String; + + public var version:Number; + + public var xmlData:XML; + + public var xmlAtts:XML; + + public var currentDate:Date; + + public var results:ArrayCollection; + + public function APITestObject(id:Number) + { + this.id = id; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Address.as b/testSrc/com/googlecode/testData/Address.as new file mode 100644 index 0000000..bcfc2fd --- /dev/null +++ b/testSrc/com/googlecode/testData/Address.as @@ -0,0 +1,36 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + public class Address + { + public var person:Person; + + public var emailAddress:String; + + public var telephoneNumbers:Array; + + public var street:String; + + public var number:String; + + public var city:String; + + public var country:String; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/AnotherVP.as b/testSrc/com/googlecode/testData/AnotherVP.as new file mode 100644 index 0000000..fdb5d6d --- /dev/null +++ b/testSrc/com/googlecode/testData/AnotherVP.as @@ -0,0 +1,15 @@ +package com.googlecode.testData +{ + public class AnotherVP + { + [XmlAttribute()] + public var id:String = "4"; + + [XmlElement(alias="tester")] + public var path:XmlPathObject; + + public function AnotherVP() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/ArrayListItem.as b/testSrc/com/googlecode/testData/ArrayListItem.as new file mode 100644 index 0000000..d6923f4 --- /dev/null +++ b/testSrc/com/googlecode/testData/ArrayListItem.as @@ -0,0 +1,18 @@ +package com.googlecode.testData +{ + import mx.collections.ArrayList; + + [XmlClass] + public class ArrayListItem + { + [XmlAttribute()] + public var id:String; + + [XmlArray(alias="arrayList", memberName="item", type="String")] + public var list:ArrayList; + + public function ArrayListItem() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Company.as b/testSrc/com/googlecode/testData/Company.as new file mode 100644 index 0000000..9c0f81a --- /dev/null +++ b/testSrc/com/googlecode/testData/Company.as @@ -0,0 +1,31 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + public class Company + { + [XmlArray(getRuntimeType="true")] + public var employees:Array; + + [XmlArray(getRuntimeType="true")] + public var departments:Array; + + public function Company() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/ConstructorRefObj.as b/testSrc/com/googlecode/testData/ConstructorRefObj.as new file mode 100644 index 0000000..48059c7 --- /dev/null +++ b/testSrc/com/googlecode/testData/ConstructorRefObj.as @@ -0,0 +1,41 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + [XmlClass] + [ConstructorArg(reference="ref1", optional="false")] + [ConstructorArg(reference="ref2")] + [ConstructorArg(reference="ref3", optional="true")] + [Bindable] + public class ConstructorRefObj + { + [XmlElement] + public var ref1:String; + [XmlAttribute] + public var ref2:Number; + [XmlAttribute] + public var ref3:Boolean; + + public function ConstructorRefObj(r1:String, r2:Number, r3:Boolean) + { + ref1 = r1; + ref2 = r2; + ref3 = r3; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/CustomSerializabeObject.as b/testSrc/com/googlecode/testData/CustomSerializabeObject.as new file mode 100644 index 0000000..b183d00 --- /dev/null +++ b/testSrc/com/googlecode/testData/CustomSerializabeObject.as @@ -0,0 +1,58 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + import com.googlecode.flexxb.interfaces.ISerializable; + + public class CustomSerializabeObject implements ISerializable + { + public var test:String; + + public function CustomSerializabeObject() + { + } + + public function get id():String + { + return null; + } + + public function serialize():XML + { + return + {test} + ; + } + + public function get thisType():Class + { + return CustomSerializabeObject; + } + + public function deserialize(serializedData:XML):* + { + var xmlData:XML = serializedData as XML; + test = xmlData.testField; + return this; + } + + public function getIdValue(serializedData:XML):String + { + return null; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/DefaultValueTestObj.as b/testSrc/com/googlecode/testData/DefaultValueTestObj.as new file mode 100644 index 0000000..75e372e --- /dev/null +++ b/testSrc/com/googlecode/testData/DefaultValueTestObj.as @@ -0,0 +1,33 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + public class DefaultValueTestObj + { + [XmlElement()] + public var date:Date; + + [XmlAttribute(default="MyValue")] + public var string:String; + + [XmlElement(default="1")] + public var min:Number; + + [XmlElement(default="5")] + public var max:int; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Department.as b/testSrc/com/googlecode/testData/Department.as new file mode 100644 index 0000000..4852793 --- /dev/null +++ b/testSrc/com/googlecode/testData/Department.as @@ -0,0 +1,34 @@ +package com.googlecode.testData +{ + import com.googlecode.flexxb.interfaces.ICycleRecoverable; + + import flash.events.Event; + import flash.events.EventDispatcher; + + [XmlClass(idField="id")] + public final class Department extends EventDispatcher implements ICycleRecoverable + { + public static const CYCLE_DETECTED:String = "CycleDetectedEvent"; + + [XmlAttribute] + public var id:Number; + + [XmlAttribute] + public var name:String; + + [XmlArray] + public var employees:Array; + + public function Department() + { + } + + public function onCycleDetected(parentCaller:Object):Object + { + var copy:Department = new Department(); + copy.id = id; + dispatchEvent(new Event(CYCLE_DETECTED)); + return copy; + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/DepartmentEmployee.as b/testSrc/com/googlecode/testData/DepartmentEmployee.as new file mode 100644 index 0000000..faf808c --- /dev/null +++ b/testSrc/com/googlecode/testData/DepartmentEmployee.as @@ -0,0 +1,15 @@ +package com.googlecode.testData +{ + public final class DepartmentEmployee + { + [XmlAttribute] + public var name:String; + + [XmlElement] + public var department:Department; + + public function DepartmentEmployee() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/IdentifiableObject.as b/testSrc/com/googlecode/testData/IdentifiableObject.as new file mode 100644 index 0000000..c0a9ba8 --- /dev/null +++ b/testSrc/com/googlecode/testData/IdentifiableObject.as @@ -0,0 +1,31 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + [XmlClass(alias="Identidiable", idField="identification")] + public class IdentifiableObject + { + [XmlElement(alias="Id")] + public var identification:String; + + public function IdentifiableObject() + { + } + + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/List.as b/testSrc/com/googlecode/testData/List.as new file mode 100644 index 0000000..e11da4c --- /dev/null +++ b/testSrc/com/googlecode/testData/List.as @@ -0,0 +1,35 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + public class List + { + [XmlArray(alias="nums", type="int", memberName="n")] + public var nums:Array = new Array(); + + [XmlArray(alias="items", type="String")] + public var items:Array = new Array(); + + [XmlArray(alias="nbrs", type="int")] + public var numbers:Array = new Array(); + + public function List() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/MGM.as b/testSrc/com/googlecode/testData/MGM.as new file mode 100644 index 0000000..917d766 --- /dev/null +++ b/testSrc/com/googlecode/testData/MGM.as @@ -0,0 +1,21 @@ +package com.googlecode.testData +{ + import mx.collections.ArrayCollection; + + [Namespace(prefix="mgm", uri="http://www.mgm.com/app")] + [XmlClass(alias="Response", prefix="mgm")] + public class MGM + { + + public function MGM() + { + } + + [XmlElement(alias="id", namespace="mgm")] + public var id:String; + + [XmlArray(alias="fields", namespace="")] + public var fields:ArrayCollection; + } + +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/ManyDates.as b/testSrc/com/googlecode/testData/ManyDates.as new file mode 100644 index 0000000..3d00713 --- /dev/null +++ b/testSrc/com/googlecode/testData/ManyDates.as @@ -0,0 +1,14 @@ +package com.googlecode.testData +{ + [XmlClass(alias="theDates")] + public class ManyDates + { + [XmlArray(memberName="dateItem", type="Date")] + [ArrayElementType("Date")] + public var dates:Array; + + public function ManyDates() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Mock.as b/testSrc/com/googlecode/testData/Mock.as new file mode 100644 index 0000000..f7ec8c3 --- /dev/null +++ b/testSrc/com/googlecode/testData/Mock.as @@ -0,0 +1,64 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + [Bindable] + [XmlClass(alias="MyClass", prefix="test", uri="http://www.test.com/xmlns/pp/v1")] + [XmlClass(alias="V2", version="v2", prefix="ulala", uri="www.me.com")] + [Namespace(prefix="me", uri="www.me.com")] + public class Mock + { + [XmlAttribute(alias="stuff")] + public var aField:String = "a"; + [XmlAttribute(ignoreOn="serialize")] + public var date:Date; + [XmlAttribute(version="v2")] + [XmlElement(alias="objVersion", namespace="me")] + public var version:int = 4; + [XmlElement(version="v2", alias="v2Tested")] + [XmlElement(alias="mock3", serializePartialElement="true")] + public var link:Mock3; + [XmlElement(serializePartialElement="true")] + public var reference:Object; + [XmlElement()] + public var classType:Class; + [XmlArray(alias="data", type="com.googlecode.testData.Mock")] + public var result:Array; + + internal var internalTest:String; + + [XmlElement] + public function get readOnly():String + { + return "YES"; + } + + [XmlElement()] + public function set writeOnly(value:String):void + { + trace("Mock - writeOnly"); + } + + public var someExcludedField:Boolean; + + [Argument(ref="version", optional="false")] + public function Mock() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Mock2.as b/testSrc/com/googlecode/testData/Mock2.as new file mode 100644 index 0000000..a119588 --- /dev/null +++ b/testSrc/com/googlecode/testData/Mock2.as @@ -0,0 +1,30 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + [XmlClass(alias="MyMock", prefix="meee", uri="http://www.axway.com/xmlns/passport/v1/meee")] + public class Mock2 + { + [XmlAttribute] + public var id:Number = 3; + + public function Mock2() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Mock3.as b/testSrc/com/googlecode/testData/Mock3.as new file mode 100644 index 0000000..2284a80 --- /dev/null +++ b/testSrc/com/googlecode/testData/Mock3.as @@ -0,0 +1,35 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + [XmlClass(alias="MOck2Replacement", idField="id")] + public class Mock3 extends Mock2 + { + [XmlAttribute] + public var attribute:Boolean; + [XmlElement(alias="objectVersion")] + public var version:Number; + [XmlArray] + public var list:Array = [1, 2, 3]; + + public function Mock3() + { + super(); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Mock4.as b/testSrc/com/googlecode/testData/Mock4.as new file mode 100644 index 0000000..a470993 --- /dev/null +++ b/testSrc/com/googlecode/testData/Mock4.as @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2010 Axway Inc. All Rights Reserved. + * Please refer to the file "LICENSE" for further important copyright + * and licensing information. Please also refer to the documentation + * for additional copyright notices. + * + * @author aciobanu + */ +package com.googlecode.testData +{ + import com.googlecode.flexxb.cache.IPooledObject; + + import flash.events.Event; + import flash.events.EventDispatcher; + import flash.events.IEventDispatcher; + + /** + * + */ + [Event(name="clear", type="flash.events.Event")] + /** + * + * @author aciobanu + * + */ + public class Mock4 extends EventDispatcher implements IPooledObject + { + public static const CLEAR:String = "clear"; + + public function Mock4(target:IEventDispatcher = null) + { + super(target); + } + + public function get type():Object + { + return Mock4; + } + + public function clear():void + { + dispatchEvent(new Event(CLEAR)); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/NameOrdered.as b/testSrc/com/googlecode/testData/NameOrdered.as new file mode 100644 index 0000000..c2d97f8 --- /dev/null +++ b/testSrc/com/googlecode/testData/NameOrdered.as @@ -0,0 +1,36 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + [Bindable] + [XmlClass(name="OrderTest", ordered="true")] + public class NameOrdered + { + [XmlElement(alias="TestOk")] + public var isOK:Boolean = false; + [XmlElement(alias="variable")] + public var test1:int; + [XmlElement()] + public var test2:String; + [XmlAttribute()] + public var test3:String; + [XmlElement()] + public var reference:String; + [XmlArray(alias="list", memberName="testerElem")] + public var list:Array; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/NamespacedArrayMember.as b/testSrc/com/googlecode/testData/NamespacedArrayMember.as new file mode 100644 index 0000000..6c651f9 --- /dev/null +++ b/testSrc/com/googlecode/testData/NamespacedArrayMember.as @@ -0,0 +1,18 @@ +package com.googlecode.testData +{ + [XmlClass(alias="data")] + [Namespace(prefix="ns", uri="www.example.com/ns")] + [Namespace(prefix="member", uri="www.example.com/member")] + public class NamespacedArrayMember + { + [XmlArray(type="String", memberName="string", memberNamespace="member")] + public var listA:Array = new Array(); + + [XmlArray(type="int", memberName="int", namespace="ns", memberNamespace="member")] + public var listB:Array = new Array(); + + public function NamespacedArrayMember() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Node.as b/testSrc/com/googlecode/testData/Node.as new file mode 100644 index 0000000..4f0637f --- /dev/null +++ b/testSrc/com/googlecode/testData/Node.as @@ -0,0 +1,31 @@ +/** + * FlexXBTest + * Copyright (C) 2008-2012 Alex Ciobanu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.googlecode.testData +{ + [Namespace(prefix="xsi", uri="http://www.w3.org/2001/XMLSchema-instance")] + [XmlClass(name="node", uri="htp://www.w3.org/xml")] + public class Node + { + [XmlAttribute(namespace="xsi")] + public var type:String = "xml"; + + public function Node() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/Person.as b/testSrc/com/googlecode/testData/Person.as new file mode 100644 index 0000000..86a0bd3 --- /dev/null +++ b/testSrc/com/googlecode/testData/Person.as @@ -0,0 +1,41 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + /** + * + * @author Alexutz + * + */ + public class Person + { + public function Person(first:String = null, last:String = null) + { + firstName = first; + lastName = last; + } + + public var firstName:String; + + public var lastName:String; + + public var birthDate:Date; + + public var age:Number; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/PhoneNumber.as b/testSrc/com/googlecode/testData/PhoneNumber.as new file mode 100644 index 0000000..ae17a7e --- /dev/null +++ b/testSrc/com/googlecode/testData/PhoneNumber.as @@ -0,0 +1,31 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + public class PhoneNumber + { + public var countryCode:String; + + public var areaCode:String; + + public var number:String; + + public var interior:String; + + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/RequiredMembersData.as b/testSrc/com/googlecode/testData/RequiredMembersData.as new file mode 100644 index 0000000..4d12ad1 --- /dev/null +++ b/testSrc/com/googlecode/testData/RequiredMembersData.as @@ -0,0 +1,46 @@ +package com.googlecode.testData +{ + [XmlClass(alias="data")] + public class RequiredMembersData + { + [XmlAttribute(required="true")] + public var requiredAttr:String; + + [XmlAttribute(required="false")] + public var optionalAttr:String; + + [XmlElement(required="true")] + public var requiredElement:String; + + [XmlElement(required="false")] + public var optionalElement:String; + + [XmlArray(required="true", memberName="item")] + public var requiredArray:Array; + + [XmlArray(required="false", memberName="item")] + public var optionalArray:Array; + + [XmlAttribute(alias="nested/requiredAttr", required="true")] + public var requiredNestedAttr:String; + + [XmlAttribute(alias="nested/optionalAttr", required="false")] + public var optionalNestedAttr:String; + + [XmlElement(alias="nested/requiredElement", required="true")] + public var requiredNestedElement:String; + + [XmlElement(alias="nested/optionalElement", required="false")] + public var optionalNestedElement:String; + + [XmlArray(alias="nested/requiredArray", required="true", memberName="item")] + public var requiredNestedArray:Array; + + [XmlArray(alias="nested/optionalArray", required="false", memberName="item")] + public var optionalNestedArray:Array; + + public function RequiredMembersData() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/VectoredElement.as b/testSrc/com/googlecode/testData/VectoredElement.as new file mode 100644 index 0000000..7711058 --- /dev/null +++ b/testSrc/com/googlecode/testData/VectoredElement.as @@ -0,0 +1,16 @@ +package com.googlecode.testData +{ + [XmlClass] + public class VectoredElement + { + [XmlElement] + public var id:String; + + [XmlArray] + public var list:Vector.; + + public function VectoredElement() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/VersionedItem.as b/testSrc/com/googlecode/testData/VersionedItem.as new file mode 100644 index 0000000..7561677 --- /dev/null +++ b/testSrc/com/googlecode/testData/VersionedItem.as @@ -0,0 +1,25 @@ +package com.googlecode.testData +{ + [XmlClass(alias="item", uri="http://www.me.com/me/de")] + [XmlClass(version="v2")] + public class VersionedItem + { + [XmlAttribute()] + [XmlElement(version="v2")] + public var id:String; + + [XmlAttribute(alias="pName")] + [XmlAttribute(alias="itemName", version="v2")] + public var name:String; + + [XmlElement(alias="mock", version="v2")] + public var value:Mock; + + [XmlElement(alias="test", serializePartialElement="true")] + public var mock2:Mock2; + + public function VersionedItem() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/XmlPathObject.as b/testSrc/com/googlecode/testData/XmlPathObject.as new file mode 100644 index 0000000..51954a5 --- /dev/null +++ b/testSrc/com/googlecode/testData/XmlPathObject.as @@ -0,0 +1,38 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + + [XmlClass(alias="test1/t3/myPathTester", defaultValueField="defaultTest")] + public class XmlPathObject + { + [XmlElement(alias="subObject/id")] + public var identity:Number = 2; + [XmlElement(alias="subObject/subSubObj/ref")] + public var reference:String = "ReferenceTo"; + [XmlArray(alias="subObject/list")] + public var list:Array; + [XmlAttribute(alias="anotherSub/attTest")] + public var test:Date = new Date(); + [XmlElement()] + public var defaultTest:String = "This is Default!!!" + + public function XmlPathObject() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/XmlTypedObj.as b/testSrc/com/googlecode/testData/XmlTypedObj.as new file mode 100644 index 0000000..15eedf5 --- /dev/null +++ b/testSrc/com/googlecode/testData/XmlTypedObj.as @@ -0,0 +1,29 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData +{ + [XmlClass] + public class XmlTypedObj + { + [XmlElement] + public var firstXml:XML; + [XmlAttribute] + public var secondXml:XML; + [XmlElement] + public var field:int = 6; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/arrayIssue/IData.as b/testSrc/com/googlecode/testData/arrayIssue/IData.as new file mode 100644 index 0000000..2153d8f --- /dev/null +++ b/testSrc/com/googlecode/testData/arrayIssue/IData.as @@ -0,0 +1,22 @@ +package com.googlecode.testData.arrayIssue +{ + import mx.collections.ArrayCollection; + + [XmlClass(alias="data", prefix="xs")] + [Namespace(prefix="xs", uri="http://www.example.com")] + public class IData + { + + [ArrayElementType("com.googlecode.testData.arrayIssue.Item")] + [XmlArray(alias="*", type="com.googlecode.testData.arrayIssue.Item", namespace="xs")] + public var localItems:ArrayCollection = new ArrayCollection(); + + [ArrayElementType("com.googlecode.testData.arrayIssue.Item")] + [XmlArray(alias="nested", type="com.googlecode.testData.arrayIssue.Item", namespace="xs")] + public var nestedItems:ArrayCollection = new ArrayCollection(); + + public function IData() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/arrayIssue/Item.as b/testSrc/com/googlecode/testData/arrayIssue/Item.as new file mode 100644 index 0000000..1d37ff5 --- /dev/null +++ b/testSrc/com/googlecode/testData/arrayIssue/Item.as @@ -0,0 +1,16 @@ +package com.googlecode.testData.arrayIssue +{ + + [XmlClass(alias="item", prefix="xs")] + [Namespace(prefix="xs", uri="http://www.example.com")] + public class Item + { + + [XmlAttribute] + public var value:String; + + public function Item() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/derivedType/A.as b/testSrc/com/googlecode/testData/derivedType/A.as new file mode 100644 index 0000000..ffba41d --- /dev/null +++ b/testSrc/com/googlecode/testData/derivedType/A.as @@ -0,0 +1,10 @@ +package com.googlecode.testData.derivedType +{ + [XmlClass] + public class A + { + public function A() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/derivedType/B.as b/testSrc/com/googlecode/testData/derivedType/B.as new file mode 100644 index 0000000..d19384f --- /dev/null +++ b/testSrc/com/googlecode/testData/derivedType/B.as @@ -0,0 +1,11 @@ +package com.googlecode.testData.derivedType +{ + [XmlClass] + public class B extends A + { + public function B() + { + super(); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/derivedType/X.as b/testSrc/com/googlecode/testData/derivedType/X.as new file mode 100644 index 0000000..87cf005 --- /dev/null +++ b/testSrc/com/googlecode/testData/derivedType/X.as @@ -0,0 +1,10 @@ +package com.googlecode.testData.derivedType +{ + [XmlClass] + public class X + { + [XmlElement(alias="value/*", getRuntimeType="true")] + public var a:A; + } + +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/errorTest/ITest.as b/testSrc/com/googlecode/testData/errorTest/ITest.as new file mode 100644 index 0000000..34f6332 --- /dev/null +++ b/testSrc/com/googlecode/testData/errorTest/ITest.as @@ -0,0 +1,9 @@ +package com.googlecode.testData.errorTest +{ + public interface ITest + { + function getData():void; + + function setData():void; + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/errorTest/TestVO.as b/testSrc/com/googlecode/testData/errorTest/TestVO.as new file mode 100644 index 0000000..3933f7a --- /dev/null +++ b/testSrc/com/googlecode/testData/errorTest/TestVO.as @@ -0,0 +1,20 @@ +package com.googlecode.testData.errorTest +{ + [XmlClass(alias="TestVO")] + public class TestVO + { + [XmlElement(alias="intTest/*", getRuntimeType="true")] + public var intTest:ITest; + + + [XmlElement(alias="intTest1/*", getRuntimeType="true")] + public var intTest1:ITest; + + + public function TestVO() + { + + + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/errorTest/testVO6.as b/testSrc/com/googlecode/testData/errorTest/testVO6.as new file mode 100644 index 0000000..15cac46 --- /dev/null +++ b/testSrc/com/googlecode/testData/errorTest/testVO6.as @@ -0,0 +1,27 @@ +package com.googlecode.testData.errorTest +{ + [XmlClass(alias="testVO6")] + public class testVO6 implements ITest + { + + [XmlAttribute] + public var test6Inst:String = "test6"; + + + public function testVO6() + { + + + } + + + public function getData():void + { + } + + + public function setData():void + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/errorTest/testVO7.as b/testSrc/com/googlecode/testData/errorTest/testVO7.as new file mode 100644 index 0000000..f92ef10 --- /dev/null +++ b/testSrc/com/googlecode/testData/errorTest/testVO7.as @@ -0,0 +1,27 @@ +package com.googlecode.testData.errorTest +{ + [XmlClass(alias="testVO7")] + public class testVO7 implements ITest + { + + [XmlAttribute] + public var test7Inst:String = "test7"; + + + public function testVO7() + { + + + } + + + public function getData():void + { + } + + + public function setData():void + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/idref/Data.as b/testSrc/com/googlecode/testData/idref/Data.as new file mode 100644 index 0000000..3239d61 --- /dev/null +++ b/testSrc/com/googlecode/testData/idref/Data.as @@ -0,0 +1,27 @@ +package com.googlecode.testData.idref +{ + import mx.collections.ArrayCollection; + + [XmlClass(alias="data")] + public class Data + { + [XmlElement] + public var node:Node; + + + [XmlAttribute(alias="referenceAtt/id", getFromCache="true", idref="true", serializePartialElement="true")] + public var referenceAtt:Node; + + + [XmlElement(alias="referenceElement", getFromCache="true", idref="true", serializePartialElement="true")] + public var referenceElement:Node; + + [XmlArray(alias="referenceArray", memberName="node", type="com.googlecode.testData.idref.Node", getFromCache="true", idref="true", serializePartialElement="true")] + public var referenceArray:ArrayCollection; + + + public function Data() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/idref/Node.as b/testSrc/com/googlecode/testData/idref/Node.as new file mode 100644 index 0000000..5271bdc --- /dev/null +++ b/testSrc/com/googlecode/testData/idref/Node.as @@ -0,0 +1,16 @@ +package com.googlecode.testData.idref +{ + [XmlClass(alias="node", idField="id")] + public class Node + { + [XmlAttribute] + public var id:String; + + [XmlAttribute] + public var name:String; + + public function Node() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/xsi/BaseItem.as b/testSrc/com/googlecode/testData/xsi/BaseItem.as new file mode 100644 index 0000000..ba6b54b --- /dev/null +++ b/testSrc/com/googlecode/testData/xsi/BaseItem.as @@ -0,0 +1,32 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData.xsi +{ + [XmlClass] + [XmlClass(prefix="a", uri="http://test.com/xsiNS", version="xsiNS")] + [Namespace(prefix="a", uri="http://test.com/xsiNS", version="xsiNS")] + public class BaseItem + { + [XmlElement] + [XmlElement(version="xsiNS", namespace="a")] + public var element:String; + + public function BaseItem() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/xsi/ItemA.as b/testSrc/com/googlecode/testData/xsi/ItemA.as new file mode 100644 index 0000000..653be84 --- /dev/null +++ b/testSrc/com/googlecode/testData/xsi/ItemA.as @@ -0,0 +1,33 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData.xsi +{ + [XmlClass] + [XmlClass(prefix="a", uri="http://test.com/xsiNS", version="xsiNS")] + [Namespace(prefix="a", uri="http://test.com/xsiNS", version="xsiNS")] + public class ItemA extends BaseItem + { + [XmlAttribute] + [XmlAttribute(version="xsiNS")] + public var fieldA:String; + + public function ItemA() + { + super(); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/xsi/ItemB.as b/testSrc/com/googlecode/testData/xsi/ItemB.as new file mode 100644 index 0000000..db4cb74 --- /dev/null +++ b/testSrc/com/googlecode/testData/xsi/ItemB.as @@ -0,0 +1,33 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData.xsi +{ + [XmlClass] + [XmlClass(prefix="a", uri="http://test.com/xsiNS", version="xsiNS")] + [Namespace(prefix="a", uri="http://test.com/xsiNS", version="xsiNS")] + public class ItemB extends BaseItem + { + [XmlAttribute] + [XmlAttribute(version="xsiNS")] + public var fieldB:String; + + public function ItemB() + { + super(); + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/xsi/Main.as b/testSrc/com/googlecode/testData/xsi/Main.as new file mode 100644 index 0000000..d00e3e2 --- /dev/null +++ b/testSrc/com/googlecode/testData/xsi/Main.as @@ -0,0 +1,41 @@ +/** + * FlexXB - an annotation based xml serializer for Flex and Air applications + * Copyright (C) 2008-2012 Alex Ciobanu + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.googlecode.testData.xsi +{ + [XmlClass] + [XmlClass(version="xsiNS")] + [Namespace(prefix="a", uri="http://test.com/xsiNS", version="xsiNS")] + [Namespace(prefix="xsi", uri="http://www.w3.org/2001/XMLSchema-instance", version="xsiNS")] + public class Main + { + [XmlAttribute] + [XmlAttribute(version="xsiNS")] + public var id:Number = 0; + + [XmlElement(setXsiType="true", getRuntimeType="true")] + [XmlElement(setXsiType="true", getRuntimeType="true", namespace="a", version="xsiNS")] + public var property:BaseItem; + + [XmlArray(alias="members", memberName="listItem", setXsiType="true", getRuntimeType="true")] + [XmlArray(alias="members", memberName="listItem", setXsiType="true", getRuntimeType="true", namespace="a", version="xsiNS")] + public var list:Array; + + public function Main() + { + } + } +} \ No newline at end of file diff --git a/testSrc/com/googlecode/testData/xsi/nil/NillableData.as b/testSrc/com/googlecode/testData/xsi/nil/NillableData.as new file mode 100644 index 0000000..2881bef --- /dev/null +++ b/testSrc/com/googlecode/testData/xsi/nil/NillableData.as @@ -0,0 +1,34 @@ +package com.googlecode.testData.xsi.nil +{ + [XmlClass(alias="data")] + public class NillableData + { + [XmlElement(nillable="true")] + public var elementNillable:String; + + [XmlElement] + public var elementNormal:String; + + [XmlElement(required="true")] + public var elementRequired:String; + + [XmlElement(required="true", nillable="true")] + public var elementNillableRequired:String; + + [XmlElement(alias="nested/elementNillable", nillable="true")] + public var nestedElementNillbable:String; + + [XmlElement(alias="nested/elementNormal")] + public var nestedElementNormal:String; + + [XmlElement(alias="nested/elementRequired", required="true")] + public var nestedElementRequired:String; + + [XmlElement(alias="nested/elementNillableRequired", nillable="true")] + public var nestedElementNillableRequired:String; + + public function NillableData() + { + } + } +} \ No newline at end of file