/// <summary> /// Recursive method to resolve annotations in parameter class and its super classes. /// This mehthod creates field descriptors and other optimized datastructures, which /// is used for marshalling and ummarshalling of runtime objects. /// </summary> /// <param name="thatClass"> /// The parameter class <c>Type</c> to resolve any defined annotations. /// </param> /// <param name="fieldDescriptorClass"> /// Used by recursive call from inside the function. Can be null if being called /// for the first time. /// </param> public void DeriveAndOrganizeFieldsRecursive(Type thatClass) { if (XmlTools.IsAnnotationPresent <SimplInherit>(thatClass)) { TypeInfo classTypeInfo = thatClass.GetTypeInfo(); Type[] superClassGenericArguments = classTypeInfo.BaseType.GenericTypeArguments; ClassDescriptor superClassDescriptor = GetClassDescriptor(classTypeInfo.BaseType); ReferFieldDescriptorsFrom(superClassDescriptor, superClassGenericArguments); } IEnumerable <FieldInfo> fields = thatClass.GetTypeInfo().DeclaredFields; // Iterate through all fields for the type foreach (FieldInfo thatField in fields) { // We don't serialize static values in S.im.pl, continue on to the next field if ((thatField.IsStatic)) { continue; } Int16 fieldType = FieldTypes.UnsetType; if (XmlTools.IsScalar(thatField)) { fieldType = FieldTypes.Scalar; } else if (XmlTools.IsAnnotationPresent <SimplComposite>(thatField)) { fieldType = FieldTypes.CompositeElement; } else if (XmlTools.IsAnnotationPresent <SimplCollection>(thatField)) { fieldType = FieldTypes.CollectionElement; } else if (XmlTools.IsAnnotationPresent <SimplMap>(thatField)) { fieldType = FieldTypes.MapElement; } if (fieldType == FieldTypes.UnsetType) { continue; //not a simpl serialization annotated field } FieldDescriptor fieldDescriptor = NewFieldDescriptor(thatField, fieldType, fieldDescriptorClass); //generics fieldDescriptor.GenericTypeVarsContextCD = this; if (fieldDescriptor.FdType == FieldTypes.Scalar) { Hint xmlHint = fieldDescriptor.XmlHint; switch (xmlHint) { case Hint.XmlAttribute: _attributeFieldDescriptors.Add(fieldDescriptor); break; case Hint.XmlText: case Hint.XmlTextCdata: break; case Hint.XmlLeaf: case Hint.XmlLeafCdata: _elementFieldDescriptors.Add(fieldDescriptor); break; } } else { _elementFieldDescriptors.Add(fieldDescriptor); } if (XmlTools.IsCompositeAsScalarValue(thatField)) { _scalarValueFieldDescriptor = fieldDescriptor; } _fieldDescriptorsByFieldName.Add(thatField.Name, fieldDescriptor); if (fieldDescriptor.IsMarshallOnly) { continue; } String fieldTagName = fieldDescriptor.TagName; if (fieldDescriptor.IsWrapped) { FieldDescriptor wrapper = NewFieldDescriptor(fieldDescriptor, fieldTagName, fieldDescriptorClass); MapTagToFdForTranslateFrom(fieldTagName, wrapper); } else if (!fieldDescriptor.IsPolymorphic) { String tag = fieldDescriptor.IsCollection ? fieldDescriptor.CollectionOrMapTagName : fieldTagName; MapTagToFdForTranslateFrom(tag, fieldDescriptor); var otherTagsAttributes = XmlTools.GetAnnotation <SimplOtherTags>(thatField); String[] otherTags = XmlTools.OtherTags(otherTagsAttributes); if (otherTags != null) { foreach (String otherTag in otherTags) { MapTagToFdForTranslateFrom(otherTag, fieldDescriptor); } } } else { MapTagClassDescriptors(fieldDescriptor); } } }
/// <summary> /// Returns the <c>ClassDescriptor</c> associated with the class type. /// Uses the global class descriptor map to fetch the <c>ClassDescriptor</c>. /// If it is being for the first time it recusively generate <c>ClassDescriptors</c> /// and resolve annotations. /// </summary> /// <param name="thatClass"> /// <c>Type</c> of the class /// </param> /// <returns> /// <c>ClassDescripor</c> for the paramater class or <c>null</c> /// if there is no associated class descriptor. /// </returns> public static ClassDescriptor GetClassDescriptor(Type thatClass) { String className = thatClass.FullName; // for generic classes, className could be null! //generics while (thatClass.GetTypeInfo().IsGenericParameter) //e.g. where X : Media \n where I : X \n ... List<I> field; { Type[] thatClassConstraints = thatClass.GetTypeInfo().GetGenericParameterConstraints(); if (thatClassConstraints == null || thatClassConstraints.Length == 0) { thatClass = typeof(Object); } else { thatClass = thatClassConstraints[0]; } className = thatClass.FullName; } if (thatClass.GetTypeInfo().IsGenericType) //can also be a generic parameter that extends a generic type { if (thatClass.FullName == null) { className = thatClass.GetGenericTypeDefinition().FullName; } } ClassDescriptor result = null; if (!GlobalClassDescriptorsMap.TryGetValue(className, out result) || !result.IsGetAndOrganizeComplete) { lock (GlobalClassDescriptorsMap) { if (!GlobalClassDescriptorsMap.TryGetValue(className, out result)) { var descriptorsAnnotation = XmlTools.GetAnnotation <SimplDescriptorClasses>(thatClass, considerInheritedAnnotations : true); if (descriptorsAnnotation == null) { result = new ClassDescriptor(thatClass); } else { //First class is the type of the class descriptor, the second the type of the fieldDescriptor. Type classDescriptorClass = descriptorsAnnotation.Classes[0]; result = ReflectionTools.GetInstance <ClassDescriptor>(classDescriptorClass, new object[] { thatClass }); result.fieldDescriptorClass = descriptorsAnnotation.Classes[1]; } GlobalClassDescriptorsMap[className] = result; ClassDescriptor superCD = result.SuperClass; if (superCD == null || superCD.IsGetAndOrganizeComplete) { result.DeriveAndOrganizeFieldsRecursive(thatClass); result.IsGetAndOrganizeComplete = true; result.HandleFieldDescriptorsDerivedEvent(); } else { ClassDescriptor resultFinalCopy = result; superCD.FieldDescriptorsDerived += (sender, args) => { resultFinalCopy.DeriveAndOrganizeFieldsRecursive(thatClass); resultFinalCopy.IsGetAndOrganizeComplete = true; resultFinalCopy.HandleFieldDescriptorsDerivedEvent(); }; } } } } return(result); }
private int DeriveNestedSerialization(FieldInfo thatField, int annotationType) { int result = annotationType; Type thatFieldType = thatField.FieldType; switch (annotationType) { case FieldTypes.CompositeElement: String compositeTag = XmlTools.GetAnnotation <SimplComposite>(thatField).TagName; Boolean isWrap = XmlTools.IsAnnotationPresent <SimplWrap>(thatField); Boolean compositeTagIsNullOrEmpty = String.IsNullOrEmpty(compositeTag); if (!IsPolymorphic) { if (isWrap && compositeTagIsNullOrEmpty) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate [SimplComposite] " + thatField.Name + " because its tag argument is missing."; Debug.WriteLine(msg); return(FieldTypes.IgnoredAttribute); } _elementClassDescriptor = ClassDescriptor.GetClassDescriptor(thatFieldType); _elementClass = _elementClassDescriptor.DescribedClass; compositeTag = XmlTools.GetXmlTagName(thatField); } else { if (!compositeTagIsNullOrEmpty) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate [SimplComposite] " + thatField.Name + " because its tag argument is missing."; Debug.WriteLine(msg); } } compositeTagName = compositeTag; break; case FieldTypes.CollectionElement: if (!(typeof(IList).GetTypeInfo().IsAssignableFrom(thatField.FieldType.GetTypeInfo()))) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate " + "[SimplCollection] " + field.Name + " because the annotated field is not an instance of " + typeof(IList).Name + "."; Debug.WriteLine(msg); return(FieldTypes.IgnoredAttribute); } String collectionTag = XmlTools.GetAnnotation <SimplCollection>(thatField).TagName; if (!IsPolymorphic) { Type collectionElementType = GetTypeArgs(thatField, 0); if (String.IsNullOrEmpty(collectionTag)) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate [SimplCollection]" + field.Name + " because its tag argument is missing."; Debug.WriteLine(msg); return(FieldTypes.IgnoredElement); } if (collectionElementType == null) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate [SimplCollection] " + field.Name + " because the parameterized type argument for the Collection is missing."; Debug.WriteLine(msg); return(FieldTypes.IgnoredElement); } if (!TypeRegistry.ScalarTypes.Contains(collectionElementType)) { _elementClassDescriptor = ClassDescriptor.GetClassDescriptor(collectionElementType); _elementClass = _elementClassDescriptor.DescribedClass; } else { result = FieldTypes.CollectionScalar; DeriveScalarSerialization(collectionElementType, field); if (ScalarType == null) { result = FieldTypes.IgnoredElement; String msg = "Can't identify ScalarType for serialization of " + collectionElementType; Debug.WriteLine(msg); } } } else { if (!String.IsNullOrEmpty(collectionTag)) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tIgnoring argument to [SimplCollection] " + field.Name + " because it is declared polymorphic with [SimplClasses]."; } } _collectionOrMapTagName = collectionTag; collectionType = TypeRegistry.GetCollectionType(thatField); break; case FieldTypes.MapElement: if (!(typeof(IDictionary).GetTypeInfo().IsAssignableFrom(thatField.FieldType.GetTypeInfo()))) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate " + "[SimplMap] " + field.Name + " because the annotated field is not an instance of " + typeof(IDictionary).Name + "."; Debug.WriteLine(msg); return(FieldTypes.IgnoredAttribute); } String mapTag = XmlTools.GetAnnotation <SimplMap>(thatField).TagName; if (!IsPolymorphic) { Type mapElementType = GetTypeArgs(thatField, 1); if (String.IsNullOrEmpty(mapTag)) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate [SimplMap]" + field.Name + " because its tag argument is missing."; Debug.WriteLine(msg); return(FieldTypes.IgnoredElement); } if (mapElementType == null) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tCan't translate [SimplMap] " + field.Name + " because the parameterized type argument for the map is missing."; Debug.WriteLine(msg); return(FieldTypes.IgnoredElement); } if (!TypeRegistry.ScalarTypes.Contains(mapElementType)) { _elementClassDescriptor = ClassDescriptor.GetClassDescriptor(mapElementType); _elementClass = _elementClassDescriptor.DescribedClass; } } else { if (!String.IsNullOrEmpty(mapTag)) { String msg = "In " + declaringClassDescriptor.DescribedClass + "\n\tIgnoring argument to [SimplMap] " + field.Name + " because it is declared polymorphic with [SimplClasses]."; } } _collectionOrMapTagName = mapTag; collectionType = TypeRegistry.GetCollectionType(thatField); break; } switch (annotationType) { case FieldTypes.CollectionElement: case FieldTypes.MapElement: if (!XmlTools.IsAnnotationPresent <SimplNoWrap>(thatField)) { _wrapped = true; } collectionType = TypeRegistry.GetCollectionType(thatField); break; case FieldTypes.CompositeElement: if (XmlTools.IsAnnotationPresent <SimplWrap>(thatField)) { _wrapped = true; } break; } return(result); }
public FieldDescriptor(ClassDescriptor declaringClassDescriptor, FieldInfo field, int annotationType) : base(XmlTools.GetXmlTagName(field), field.Name) { this.declaringClassDescriptor = declaringClassDescriptor; this.field = field; fieldType = field.FieldType.Name; //generics if (field.FieldType.IsGenericParameter || field.FieldType.GetTypeInfo().IsGenericType) { Type realFieldType = field.FieldType; while (realFieldType.IsGenericParameter) { Type[] realFieldTypeConstraints = realFieldType.GetTypeInfo().GetGenericParameterConstraints(); if (realFieldTypeConstraints == null || realFieldTypeConstraints.Length == 0) { realFieldType = typeof(Object); break; } else { realFieldType = realFieldTypeConstraints[0]; } } fieldType = realFieldType.Name; if (realFieldType.GetTypeInfo().IsGenericType)//can also be a generic parameter that extends a generic type { int pos = fieldType.IndexOf('`'); fieldType = fieldType.Substring(0, pos); } } if (XmlTools.IsAnnotationPresent <SimplMapKeyField>(field)) { mapKeyFieldName = XmlTools.GetAnnotation <SimplMapKeyField>(field).FieldName; } DerivePolymorphicDescriptors(field); type = FieldTypes.UnsetType; if (annotationType == FieldTypes.Scalar) { type = DeriveScalarSerialization(field); } else { type = DeriveNestedSerialization(field, annotationType); } String fieldName = field.Name; StringBuilder capFieldName = new StringBuilder(fieldName); //generics Type genericType = field.DeclaringType; isGeneric = genericType.GetTypeInfo().IsGenericType || genericType.IsGenericParameter; }
/// <summary> /// Gets the Type of the tag /// </summary> /// <param name="tag"></param> /// <returns></returns> public Type GetClassByTag(String tag) { ClassDescriptor entry = GetClassDescriptorByTag(tag); return(entry == null ? null : entry.DescribedClass); }
/// <summary> /// /// </summary> /// <param name="thatClass"></param> public void AddTranslation(Type thatClass) { ClassDescriptor entry = ClassDescriptor.GetClassDescriptor(thatClass); AddTranslation(entry); }