/// <summary> /// Adds the namespace applying to the object type specified in <paramref name="wrapper"/> /// to the <paramref name="className"/> /// </summary> /// <param name="wrapper">The wrapper around the object who's namespace should be added</param> /// <param name="className">The root node of the document to which the namespace should be written</param> private XElement CreateElementWithNamespace(UdtWrapper wrapper, XName className) { XName elemName = className.OverrideNsIfEmpty(wrapper.Namespace); if (elemName.Namespace == wrapper.Namespace) RegisterNamespace(elemName.Namespace, wrapper.NamespacePrefix); else RegisterNamespace(elemName.Namespace, null); return new XElement(elemName, null); }
/// <summary> /// Gets the sequence of fields to be serialized for the specified type. This sequence is retreived according to /// the field-types specified by the user. /// </summary> /// <param name="typeWrapper">The type wrapper for the type whose serializable /// fields is going to be retreived.</param> /// <returns>the sequence of fields to be serialized for the specified type</returns> private IEnumerable<MemberWrapper> GetFieldsToBeSerialized(UdtWrapper typeWrapper) { foreach (var member in typeWrapper.UnderlyingType.GetMembers(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)) { char name0 = member.Name[0]; if ((Char.IsLetter(name0) || name0 == '_') && (member.MemberType == MemberTypes.Property || member.MemberType == MemberTypes.Field)) { if((typeWrapper.IsCollectionType || typeWrapper.IsDictionaryType)) //&& typeWrapper.IsAttributedAsNotCollection) if(ReflectionUtils.IsPartOfNetFx(member)) continue; var memInfo = new MemberWrapper(member, this); if (memInfo.IsAllowedToBeSerialized(typeWrapper.FieldsToSerialize)) { yield return memInfo; } } } }
/// <summary> /// Initializes a new instance of the <see cref="YAXSerializer"/> class. /// </summary> /// <param name="t">The type of the object being serialized/deserialized.</param> /// <param name="exceptionPolicy">The exception handling policy.</param> /// <param name="defaultExType">The exceptions are treated as the value specified, unless otherwise specified.</param> /// <param name="option">The serialization option.</param> public YAXSerializer(Type t, YAXExceptionHandlingPolicies exceptionPolicy, YAXExceptionTypes defaultExType, YAXSerializationOptions option) { m_type = t; m_exceptionPolicy = exceptionPolicy; m_defaultExceptionType = defaultExType; m_serializationOption = option; // this must be the last call m_udtWrapper = TypeWrappersPool.Pool.GetTypeWrapper(m_type, this); if (m_udtWrapper.HasNamespace) TypeNamespace = m_udtWrapper.Namespace; }
/// <summary> /// The basic method which performs the whole job of deserialization. /// </summary> /// <param name="baseElement">The element to be deserialized.</param> /// <returns>object containing the deserialized data</returns> private object DeserializeBase(XElement baseElement) { if (baseElement == null) { return m_desObject; } if (m_udtWrapper.HasCustomSerializer) { return InvokeCustomDeserializerFromElement(m_udtWrapper.CustomSerializerType, baseElement); } var realTypeAttr = baseElement.Attribute_NamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, m_documentDefaultNamespace); if (realTypeAttr != null) { Type theRealType = ReflectionUtils.GetTypeByName(realTypeAttr.Value); if (theRealType != null) { m_type = theRealType; m_udtWrapper = TypeWrappersPool.Pool.GetTypeWrapper(m_type, this); } } if (m_type.IsGenericType && m_type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>)) { return DeserializeKeyValuePair(baseElement); } if (KnownTypes.IsKnowType(m_type)) { return KnownTypes.Deserialize(baseElement, m_type, TypeNamespace); } if ((m_udtWrapper.IsTreatedAsCollection || m_udtWrapper.IsTreatedAsDictionary) && !IsCraetedToDeserializeANonCollectionMember) { if (m_udtWrapper.DictionaryAttributeInstance != null) { return DeserializeTaggedDictionaryValue(baseElement, m_udtWrapper.Alias, m_type, m_udtWrapper.CollectionAttributeInstance, m_udtWrapper.DictionaryAttributeInstance); } else { return DeserializeCollectionValue(m_type, baseElement, m_udtWrapper.Alias, m_udtWrapper.CollectionAttributeInstance); } } if (ReflectionUtils.IsBasicType(m_type)) { return ReflectionUtils.ConvertBasicType(baseElement.Value, m_type); } object o; if (m_desObject != null) o = m_desObject; else o = m_type.InvokeMember(string.Empty, BindingFlags.CreateInstance, null, null, new object[0]); bool foundAnyOfMembers = false; foreach (var member in GetFieldsToBeSerialized()) { if (!member.CanWrite) continue; if (member.IsAttributedAsDontSerialize) continue; // reset handled exceptions status m_exceptionOccurredDuringMemberDeserialization = false; string elemValue = string.Empty; // the element value gathered at the first phase XElement xelemValue = null; // the XElement instance gathered at the first phase XAttribute xattrValue = null; // the XAttribute instance gathered at the first phase // first evaluate elemValue bool createdFakeElement = false; var serializationLocation = member.SerializationLocation; if (member.IsSerializedAsAttribute) { // find the parent element from its location XAttribute attr = XMLUtils.FindAttribute(baseElement, serializationLocation, member.Alias.OverrideNsIfEmpty(TypeNamespace)); if (attr == null) // if the parent element does not exist { // loook for an element with the same name AND a yaxlib:realtype attribute XElement elem = XMLUtils.FindElement(baseElement, serializationLocation, member.Alias.OverrideNsIfEmpty(TypeNamespace)); if (elem != null && elem.Attribute_NamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, m_documentDefaultNamespace) != null) { elemValue = elem.Value; xelemValue = elem; } else { OnExceptionOccurred(new YAXAttributeMissingException( StringUtils.CombineLocationAndElementName(serializationLocation, member.Alias)), (!member.MemberType.IsValueType && m_udtWrapper.IsNotAllowdNullObjectSerialization) ? YAXExceptionTypes.Ignore : member.TreatErrorsAs); } } else { foundAnyOfMembers = true; elemValue = attr.Value; xattrValue = attr; } } else if (member.IsSerializedAsValue) { XElement elem = XMLUtils.FindLocation(baseElement, serializationLocation); if (elem == null) // such element is not found { OnExceptionOccurred(new YAXElementMissingException( serializationLocation), (!member.MemberType.IsValueType && m_udtWrapper.IsNotAllowdNullObjectSerialization) ? YAXExceptionTypes.Ignore : member.TreatErrorsAs); } else { XText[] values = elem.Nodes().OfType<XText>().ToArray(); if(values.Length <= 0) { // loook for an element with the same name AND a yaxlib:realtype attribute XElement innerelem = XMLUtils.FindElement(baseElement, serializationLocation, member.Alias.OverrideNsIfEmpty(TypeNamespace)); if (innerelem != null && innerelem.Attribute_NamespaceSafe(m_yaxLibNamespaceUri + m_trueTypeAttrName, m_documentDefaultNamespace) != null) { elemValue = innerelem.Value; xelemValue = innerelem; } else { OnExceptionOccurred(new YAXElementValueMissingException(serializationLocation), (!member.MemberType.IsValueType && m_udtWrapper.IsNotAllowdNullObjectSerialization) ? YAXExceptionTypes.Ignore : member.TreatErrorsAs); } } else { foundAnyOfMembers = true; elemValue = values[0].Value; values[0].Remove(); } } } else // if member is serialized as an xml element { bool canContinue = false; XElement elem = XMLUtils.FindElement(baseElement, serializationLocation, member.Alias.OverrideNsIfEmpty(TypeNamespace)); if (elem == null) // such element is not found { if ((member.IsTreatedAsCollection || member.IsTreatedAsDictionary) && member.CollectionAttributeInstance != null && member.CollectionAttributeInstance.SerializationType == YAXCollectionSerializationTypes.RecursiveWithNoContainingElement) { if (AtLeastOneOfCollectionMembersExists(baseElement, member)) { elem = baseElement; canContinue = true; foundAnyOfMembers = true; } else { member.SetValue(o, member.DefaultValue); continue; } } else if (!ReflectionUtils.IsBasicType(member.MemberType) && !member.IsTreatedAsCollection && !member.IsTreatedAsDictionary) { // try to fix this problem by creating a fake element, maybe all its children are placed somewhere else XElement fakeElem = XMLUtils.CreateElement(baseElement, serializationLocation, member.Alias.OverrideNsIfEmpty(TypeNamespace)); if (fakeElem != null) { createdFakeElement = true; if (AtLeastOneOfMembersExists(fakeElem, member.MemberType)) { canContinue = true; foundAnyOfMembers = true; elem = fakeElem; elemValue = elem.Value; } } } if (!canContinue) { OnExceptionOccurred(new YAXElementMissingException( StringUtils.CombineLocationAndElementName(serializationLocation, member.Alias.OverrideNsIfEmpty(TypeNamespace))), (!member.MemberType.IsValueType && m_udtWrapper.IsNotAllowdNullObjectSerialization) ? YAXExceptionTypes.Ignore : member.TreatErrorsAs); } } else { foundAnyOfMembers = true; elemValue = elem.Value; } xelemValue = elem; } // Phase2: Now try to retrieve elemValue's value, based on values gathered in xelemValue, xattrValue, and elemValue if (m_exceptionOccurredDuringMemberDeserialization) { if (m_desObject == null) // i.e. if it was NOT resuming deserialization, set default value, otherwise existing value for the member is kept { if (!member.MemberType.IsValueType && m_udtWrapper.IsNotAllowdNullObjectSerialization) { try { member.SetValue(o, null); } catch { OnExceptionOccurred( new YAXDefaultValueCannotBeAssigned(member.Alias.LocalName, member.DefaultValue), m_defaultExceptionType); } } else if (member.DefaultValue != null) { try { member.SetValue(o, member.DefaultValue); } catch { OnExceptionOccurred( new YAXDefaultValueCannotBeAssigned(member.Alias.LocalName, member.DefaultValue), m_defaultExceptionType); } } else { if (!member.MemberType.IsValueType) { member.SetValue(o, null /*the value to be assigned */); } } } } else if (member.HasCustomSerializer || member.MemberTypeWrapper.HasCustomSerializer) { Type deserType = member.HasCustomSerializer ? member.CustomSerializerType : member.MemberTypeWrapper.CustomSerializerType; object desObj; if (member.IsSerializedAsAttribute) { desObj = InvokeCustomDeserializerFromAttribute(deserType, xattrValue); } else if (member.IsSerializedAsElement) { desObj = InvokeCustomDeserializerFromElement(deserType, xelemValue); } else if (member.IsSerializedAsValue) { desObj = InvokeCustomDeserializerFromValue(deserType, elemValue); } else { throw new Exception("unknown situation"); } try { member.SetValue(o, desObj); } catch { OnExceptionOccurred(new YAXPropertyCannotBeAssignedTo(member.Alias.LocalName), m_defaultExceptionType); } } else if (elemValue != null) { RetreiveElementValue(o, member, elemValue, xelemValue); if (createdFakeElement && !m_exceptionOccurredDuringMemberDeserialization) foundAnyOfMembers = true; } if (createdFakeElement && xelemValue != null) { // remove the fake element xelemValue.Remove(); } if(RemoveDeserializedXmlNodes) { if(xattrValue != null) xattrValue.Remove(); else if(xelemValue != null) xelemValue.Remove(); } } //// if an empty element was given and non of its members have been retreived then return null, not an instance //if (!foundAnyOfMembers && !baseElement.HasElements && !baseElement.HasAttributes && baseElement.IsEmpty) // return null; return o; }
/// <summary> /// Gets the type wrapper corresponding to the specified type. /// </summary> /// <param name="t">The type whose wrapper is needed.</param> /// <param name="caller">reference to the serializer instance which called this method.</param> /// <returns>the type wrapper corresponding to the specified type</returns> public UdtWrapper GetTypeWrapper(Type t, YAXSerializer caller) { lock (m_lockDic) { UdtWrapper result; if (!m_dicTypes.TryGetValue(t, out result)) { result = new UdtWrapper(t, caller); m_dicTypes.Add(t, result); } else { result.SetYAXSerializerOptions(caller); } return result; } }
/// <summary> /// Initializes a new instance of the <see cref="MemberWrapper"/> class. /// </summary> /// <param name="memberInfo">The member-info to build this instance from.</param> /// <param name="callerSerializer">The caller serializer.</param> public MemberWrapper(MemberInfo memberInfo, YAXSerializer callerSerializer) { if (!(memberInfo.MemberType == MemberTypes.Property || memberInfo.MemberType == MemberTypes.Field)) throw new Exception("Member must be either property or field"); m_memberInfo = memberInfo; m_isProperty = (memberInfo.MemberType == MemberTypes.Property); Alias = StringUtils.RefineSingleElement(m_memberInfo.Name); if (m_isProperty) m_propertyInfoInstance = (PropertyInfo)memberInfo; else m_fieldInfoInstance = (FieldInfo)memberInfo; m_memberType = m_isProperty ? m_propertyInfoInstance.PropertyType : m_fieldInfoInstance.FieldType; m_memberTypeWrapper = TypeWrappersPool.Pool.GetTypeWrapper(MemberType, callerSerializer); if (m_memberTypeWrapper.HasNamespace) { Namespace = m_memberTypeWrapper.Namespace; NamespacePrefix = m_memberTypeWrapper.NamespacePrefix; } InitInstance(); TreatErrorsAs = callerSerializer != null ? callerSerializer.DefaultExceptionType : YAXExceptionTypes.Error; // discovver YAXCustomSerializerAttributes earlier, because some other attributes depend on it var attrsToProcessEarlier = new HashSet<Type> {typeof (YAXCustomSerializerAttribute), typeof (YAXCollectionAttribute)}; foreach (var attrType in attrsToProcessEarlier) { var customSerAttrs = m_memberInfo.GetCustomAttributes(attrType, true); foreach (var attr in customSerAttrs) { ProcessYaxAttribute(attr); } } foreach (var attr in m_memberInfo.GetCustomAttributes(true)) { // no need to preces, it has been proccessed earlier if (attrsToProcessEarlier.Contains(attr.GetType())) continue; if (attr is YAXBaseAttribute) ProcessYaxAttribute(attr); } // now override some values from memeber-type-wrapper into member-wrapper // if member-type has collection attributes while the member itself does not have them, // then use those of the member-type if (m_collectionAttributeInstance == null && m_memberTypeWrapper.CollectionAttributeInstance != null) m_collectionAttributeInstance = m_memberTypeWrapper.CollectionAttributeInstance; if (m_dictionaryAttributeInstance == null && m_memberTypeWrapper.DictionaryAttributeInstance != null) m_dictionaryAttributeInstance = m_memberTypeWrapper.DictionaryAttributeInstance; }