/// <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);
        }
Example #3
0
        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);
        }
Example #4
0
        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);
        }