/// <summary> /// Registers a class mapping. /// </summary> /// <param name="classMapping">The class mapping data</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="classMapping"/> is null</exception> /// <exception cref="ActionScriptException">Thrown if the mapped native type /// or its ActionScript alias have already been registered with different mappings</exception> public void RegisterClassMapping(ActionScriptClassMapping classMapping) { if (classMapping == null) { throw new ArgumentNullException("classMapping"); } lock (syncRoot) { if (classMappingsByType.ContainsKey(classMapping.NativeType)) { throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Cannot register class mapping because there is already a mapper registered (or cached) for native type '{0}'.", classMapping.NativeType)); } if (classMappingsByAlias.ContainsKey(classMapping.ASClass.ClassAlias)) { throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Cannot register class mapping because there is already a mapper registered (or cached) for class alias '{0}'.", classMapping.ASClass.ClassAlias)); } // Now having validated the changes, apply them. classMappingsByType.Add(classMapping.NativeType, classMapping); string classAlias = classMapping.ASClass.ClassAlias; if (classAlias.Length != 0) { classMappingsByAlias.Add(classAlias, classMapping); } } }
/// <summary> /// Registers a type for serialization with the specified class alias. /// </summary> /// <remarks> /// This method is equivalent to calling <see cref="ActionScriptMappingReflector.CreateClassMapping" /> /// followed by <see cref="RegisterClassMapping" />. /// It serves a similar purpose to the "flex.net.registerClassAlias" method on the client side. /// </remarks> /// <param name="nativeType">The native type</param> /// <param name="classAliasOverride">The ActionScript class alias</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="nativeType"/> is null</exception> /// <exception cref="ActionScriptException">Thrown if the mapped native type /// or the class alias have already been registered with different mappings</exception> /// <exception cref="ActionScriptException">Thrown when an error occurs generating the class mapping</exception> public void RegisterType(Type nativeType, string classAliasOverride) { if (nativeType == null) { throw new ArgumentNullException("nativeType"); } ActionScriptClassMapping classMapping = ActionScriptMappingReflector.CreateClassMapping(nativeType, classAliasOverride); RegisterClassMapping(classMapping); }
/// <inheritdoc /> public override IASTargetMapper GetASTargetMapper(ASTargetMappingDescriptor descriptor) { ActionScriptClassMapping classMapping = mappingTable.GetClassMappingByType(descriptor.SourceNativeType); if (classMapping != null) { return(new ObjectMapper(classMapping)); } return(null); }
/// <inheritdoc /> public override IASSourceMapper GetASSourceMapper(ASSourceMappingDescriptor descriptor) { if (descriptor.SourceKind == ASTypeKind.Object) { ActionScriptClassMapping classMapping = mappingTable.GetClassMappingByAlias(descriptor.SourceClassAlias); if (classMapping != null && descriptor.TargetNativeType.IsAssignableFrom(classMapping.NativeType)) { return(new ObjectMapper(classMapping)); } } return(null); }
/// <summary> /// Generates class mappings for all public types in the specified assembly /// that are decorated with the <see cref="ActionScriptClassAttribute" />. /// </summary> /// <param name="assembly">The assembly to search for serializable types</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="assembly"/> is null</exception> /// <returns>The enumeration of class mappings</returns> public static IEnumerable <ActionScriptClassMapping> GetClassMappingsForTypesInAssembly(Assembly assembly) { if (assembly == null) { throw new ArgumentNullException("assembly"); } foreach (Type type in assembly.GetExportedTypes()) { ActionScriptClassAttribute classAttribute = GetActionScriptClassAttribute(type); if (classAttribute != null) { ActionScriptClassMapping classMapping = InternalCreateDefaultClassMapping(type, null, classAttribute); yield return(classMapping); } } }
private static ActionScriptClassMapping InternalCreateDefaultClassMapping(Type nativeType, string classAliasOverride, ActionScriptClassAttribute classAttribute) { // Determine the class alias. string classAlias; if (classAliasOverride != null) classAlias = classAliasOverride; else if (classAttribute != null) classAlias = classAttribute.ClassAlias; else classAlias = ""; // Determine the class layout. ASClassLayout classLayout = ASClassLayout.Normal; if (typeof(IDynamic).IsAssignableFrom(nativeType)) { classLayout = ASClassLayout.Dynamic; } if (typeof(IExternalizable).IsAssignableFrom(nativeType)) { if (classAlias.Length == 0) throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Type '{0}' implements IExternalizable but does not have a non-empty class alias name which is required by the externalizable serialization protocol.", nativeType.FullName)); if (classLayout == ASClassLayout.Dynamic) throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Type '{0}' implements IExternalizable as well as IDynamic which is not supported by the externalizable serialization protocol.", nativeType.FullName)); classLayout = ASClassLayout.Externalizable; } // Populate the list of property mappings. List<ActionScriptPropertyMapping> propertyMappings = new List<ActionScriptPropertyMapping>(); List<string> memberNames = new List<string>(); foreach (PropertyInfo property in nativeType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { AddPropertyMappingIfNeeded(property, propertyMappings, memberNames, ref classLayout); } foreach (FieldInfo field in nativeType.GetFields(BindingFlags.Instance | BindingFlags.Public)) { AddPropertyMappingIfNeeded(field, propertyMappings, memberNames, ref classLayout); } // Finish up. // Convert the lists to arrays to reduce the memory footprint. string[] memberNamesArray = memberNames.Count == 0 ? EmptyArray<string>.Instance : memberNames.ToArray(); ActionScriptPropertyMapping[] propertyMappingsArray = propertyMappings.Count == 0 ? EmptyArray<ActionScriptPropertyMapping>.Instance : propertyMappings.ToArray(); ASClass classDefinition = ASClassCache.GetClass(classAlias, classLayout, memberNamesArray); ActionScriptClassMapping classMapping = new ActionScriptClassMapping(nativeType, classDefinition, propertyMappingsArray); return classMapping; }
/// <summary> /// Registers a class mapping. /// </summary> /// <param name="classMapping">The class mapping data</param> /// <exception cref="ArgumentNullException">Thrown if <paramref name="classMapping"/> is null</exception> /// <exception cref="ActionScriptException">Thrown if the mapped native type /// or its ActionScript alias have already been registered with different mappings</exception> public void RegisterClassMapping(ActionScriptClassMapping classMapping) { if (classMapping == null) throw new ArgumentNullException("classMapping"); lock (syncRoot) { if (classMappingsByType.ContainsKey(classMapping.NativeType)) throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Cannot register class mapping because there is already a mapper registered (or cached) for native type '{0}'.", classMapping.NativeType)); if (classMappingsByAlias.ContainsKey(classMapping.ASClass.ClassAlias)) throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Cannot register class mapping because there is already a mapper registered (or cached) for class alias '{0}'.", classMapping.ASClass.ClassAlias)); // Now having validated the changes, apply them. classMappingsByType.Add(classMapping.NativeType, classMapping); string classAlias = classMapping.ASClass.ClassAlias; if (classAlias.Length != 0) classMappingsByAlias.Add(classAlias, classMapping); } }
private static ActionScriptClassMapping InternalCreateDefaultClassMapping(Type nativeType, string classAliasOverride, ActionScriptClassAttribute classAttribute) { // Determine the class alias. string classAlias; if (classAliasOverride != null) { classAlias = classAliasOverride; } else if (classAttribute != null) { classAlias = classAttribute.ClassAlias; } else { classAlias = ""; } // Determine the class layout. ASClassLayout classLayout = ASClassLayout.Normal; if (typeof(IDynamic).IsAssignableFrom(nativeType)) { classLayout = ASClassLayout.Dynamic; } if (typeof(IExternalizable).IsAssignableFrom(nativeType)) { if (classAlias.Length == 0) { throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Type '{0}' implements IExternalizable but does not have a non-empty class alias name which is required by the externalizable serialization protocol.", nativeType.FullName)); } if (classLayout == ASClassLayout.Dynamic) { throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Type '{0}' implements IExternalizable as well as IDynamic which is not supported by the externalizable serialization protocol.", nativeType.FullName)); } classLayout = ASClassLayout.Externalizable; } // Populate the list of property mappings. List <ActionScriptPropertyMapping> propertyMappings = new List <ActionScriptPropertyMapping>(); List <string> memberNames = new List <string>(); foreach (PropertyInfo property in nativeType.GetProperties(BindingFlags.Instance | BindingFlags.Public)) { AddPropertyMappingIfNeeded(property, propertyMappings, memberNames, ref classLayout); } foreach (FieldInfo field in nativeType.GetFields(BindingFlags.Instance | BindingFlags.Public)) { AddPropertyMappingIfNeeded(field, propertyMappings, memberNames, ref classLayout); } // Finish up. // Convert the lists to arrays to reduce the memory footprint. string[] memberNamesArray = memberNames.Count == 0 ? EmptyArray <string> .Instance : memberNames.ToArray(); ActionScriptPropertyMapping[] propertyMappingsArray = propertyMappings.Count == 0 ? EmptyArray <ActionScriptPropertyMapping> .Instance : propertyMappings.ToArray(); ASClass classDefinition = ASClassCache.GetClass(classAlias, classLayout, memberNamesArray); ActionScriptClassMapping classMapping = new ActionScriptClassMapping(nativeType, classDefinition, propertyMappingsArray); return(classMapping); }
/// <summary> /// Gets the default native type to use for mapping ActionScript values with certain properties. /// </summary> /// <remarks> /// The default native type can be used when insufficient type information is available to /// perform a mapping unambiguously. /// </remarks> /// <param name="kind">The value's kind</param> /// <param name="classAlias">The value's class alias or an empty string if none</param> /// <param name="contentFlags">The value's content flags</param> /// <returns>The default native type</returns> public Type GetDefaultNativeType(ASTypeKind kind, string classAlias, ASValueContentFlags contentFlags) { switch (kind) { case ASTypeKind.Array: if ((contentFlags & ASValueContentFlags.HasDynamicProperties) == 0) { return(typeof(object[])); } if ((contentFlags & ASValueContentFlags.HasIndexedValues) == 0) { return(typeof(Dictionary <string, object>)); } return(typeof(MixedArray <object>)); case ASTypeKind.Boolean: return(typeof(bool)); case ASTypeKind.ByteArray: return(typeof(byte[])); case ASTypeKind.Date: return(typeof(DateTime)); case ASTypeKind.Int29: return(typeof(int)); case ASTypeKind.Null: return(typeof(object)); case ASTypeKind.Number: return(typeof(double)); case ASTypeKind.Object: if (classAlias.Length != 0) { ActionScriptClassMapping classMapping = GetClassMappingByAlias(classAlias); if (classMapping != null) { return(classMapping.NativeType); } } // Map untyped and unknown objects to dictionaries. return(typeof(Dictionary <string, object>)); case ASTypeKind.String: return(typeof(string)); case ASTypeKind.Undefined: return(typeof(ASUndefined)); case ASTypeKind.Unsupported: return(typeof(ASUnsupported)); case ASTypeKind.Xml: return(typeof(XmlDocument)); default: throw new ActionScriptException(String.Format(CultureInfo.CurrentCulture, "Unsupported type kind '{0}'.", kind)); } }
public ObjectMapper(ActionScriptClassMapping classMapping) { this.classMapping = classMapping; PopulateTables(); }