示例#1
0
        /// <summary>
        /// Creates and populates a new instance of the generic type given in the supplied GenericTypeElementDefinition,
        /// using the supplied XML element as the source.
        /// </summary>
        /// <param name="genericTypeDefinition">The definition of the generic type to be created.</param>
        /// <param name="sourceElement">The source XML element for this object.</param>
        /// <param name="parentObject">The parent object of this object.</param>
        /// <returns>A new instance of the required type, typically of the form SomeType&lt;&gt;.</returns>
        /// <remarks>The inner type of the target type is specified via an attribute on the supplied input XML element.</remarks>
        /// <exception cref="MissingMandatoryValueException">Thrown when...<ul>
        /// <li></li>
        /// </ul></exception>
        private object CreateObject(GenericTypeElementDefinition genericTypeDefinition, XElement sourceElement, object parentObject)
        {
            _log.DebugFormat("CreateObject(GenericTypeElementDefinition, XElement) called; ElementName='{0}'.", genericTypeDefinition.ElementName);

            object[] constructorParameterValues;
            Type[]   constructorParameterTypes;

            GetConstructorParameters(genericTypeDefinition, sourceElement, parentObject, out constructorParameterTypes, out constructorParameterValues);

            string innerTypeName = ReadAttribute(sourceElement.Attributes(), genericTypeDefinition.AttributeForInnerType, typeof(string)) as string;

            if (string.IsNullOrEmpty(innerTypeName))
            {
                throw ThrowHelper.New <MissingMandatoryValueException>(this, new ExceptionInfo(sourceElement), ErrorMessages.MissingMandatoryAttribute,
                                                                       genericTypeDefinition.AttributeForInnerType.LocalName, genericTypeDefinition.ElementName.LocalName);
            }

            Type innerType;

            if (string.IsNullOrEmpty(genericTypeDefinition.InnerTypeNamespace))
            {
                innerType = Type.GetType(innerTypeName);
            }
            else
            {
                innerType = Type.GetType(string.Format("{0}.{1}", genericTypeDefinition.InnerTypeNamespace, innerTypeName));
            }

            if (innerType == null)
            {
                throw ThrowHelper.New <InvalidFieldValueException>(this, new ExceptionInfo(sourceElement), ErrorMessages.UnrecognisedTypeError, innerTypeName,
                                                                   genericTypeDefinition.AttributeForInnerType.LocalName, genericTypeDefinition.ElementName.LocalName);
            }

            object newObject = CreateRawObject(genericTypeDefinition.TargetType, new Type[] { innerType }, constructorParameterTypes, constructorParameterValues);

            IEnumerable <XAttribute> attributes = sourceElement.Attributes();

            try
            {
                ProcessAttributes(newObject.GetType(), genericTypeDefinition.Attributes, attributes, newObject);
                ProcessAttributes(newObject.GetType(), genericTypeDefinition.InnerTypeToAttributesMap[innerType], attributes, newObject);
            }
            catch (MissingMandatoryValueException ex)
            {
                throw ThrowHelper.Rethrow(this, ex, new ExceptionInfo(sourceElement), ErrorMessages.GeneralElementProcessingError, string.Empty);
            }

            ProcessChildren(genericTypeDefinition, sourceElement, newObject);

            if (newObject.GetType() == _notifyCreationOfType)
            {
                NotifyClassDeserialized(_notifyCreationOfType, newObject);
            }

            return(newObject);
        }
示例#2
0
        private static object CreateRawObject(Type targetType, Type[] argTypes, params object[] args)
        {
            _log.DebugFormat("CreateObject(Type, Type[], params object[]) called; Type={0}.", targetType.FullName);

            ConstructorInfo classConstructor = targetType.GetConstructor(argTypes);

            if (classConstructor == null)
            {
                throw ThrowHelper.New <InternalErrorException>(ExceptionContext, InternalErrors.NoConstructorFoundForSpecifiedArgumentTypes, targetType.FullName);
            }

            return(classConstructor.Invoke(args));
        }
示例#3
0
        private void ProcessChildProperty(ChildElementDefinition childDefinition, PropertyInfo property, Type targetType, object target, object childObject)
        {
            _log.DebugFormat("ProcessChildProperty called; ElementName='{0}', Property={1}.", childDefinition.ElementDefinition.ElementName, property.Name);

            string containerMethod;

            if (childDefinition.ContainerMethod is StandardContainerMethod)
            {
                StandardContainerMethod method = (StandardContainerMethod)childDefinition.ContainerMethod;

                if (method == StandardContainerMethod.Assign)
                {
                    SetPropertyValue(property, target, childObject);

                    return;
                }
                else
                {
                    containerMethod = Enum.GetName(typeof(StandardContainerMethod), childDefinition.ContainerMethod);
                }
            }
            else
            {
                containerMethod = childDefinition.ContainerMethod as string;
            }

            MethodInfo targetMethod = property.PropertyType.GetMethod(containerMethod, new Type[] { targetType });

            if (targetMethod == null)
            {
                throw ThrowHelper.New <InternalErrorException>(this, InternalErrors.ContainerMethodNotFoundOnObject,
                                                               containerMethod, targetType.FullName);
            }
            try
            {
                targetMethod.Invoke(property.GetValue(target, null), new object[] { childObject });
            }
            catch (TargetInvocationException ex)
            {
                if (ex.InnerException != null)
                {
                    throw ThrowHelper.Rethrow(this, ex.InnerException, ErrorMessages.UnableToInvokeMethodError,
                                              string.Format("the {0} method on the {1} property", containerMethod, property.Name));
                }
                else
                {
                    throw;
                }
            }
        }
示例#4
0
        private static object CreateRawObject(Type outerType, Type[] innerTypes, Type[] argTypes, params object[] args)
        {
            _log.DebugFormat("CreateObject(Type, Type[], Type[], params object[]) called (creating generic type); Outer type={0}.", outerType.FullName);

            Type specificType = outerType.MakeGenericType(innerTypes);

            ConstructorInfo classConstructor = specificType.GetConstructor(argTypes);

            if (classConstructor == null)
            {
                throw ThrowHelper.New <InternalErrorException>(ExceptionContext, InternalErrors.NoConstructorFoundForSpecifiedArgumentTypes, outerType.FullName);
            }

            return(classConstructor.Invoke(args));
        }
示例#5
0
        private static object ReadAttribute(IEnumerable <XAttribute> attributes, XName attributeName, Type enumType, Dictionary <string, Enum> enumValues)
        {
            _log.DebugFormat("ReadAttribute(IEnumerable<XAttribute>, XName, Type, Dictionary<string, Enum>) called; Attribute name='{0}'", attributeName);

            XAttribute attribute = attributes.FirstOrDefault(a => a.Name == attributeName);

            if (attribute == null)
            {
                return(null);
            }

            if (!enumValues.ContainsKey(attribute.Value))
            {
                throw ThrowHelper.New <InvalidFieldValueException>(ExceptionContext, ErrorMessages.InvalidValueEnumParseFailure, attribute.Value, enumType.Name);
            }

            return(Enum.ToObject(enumType, enumValues[attribute.Value]));
        }
示例#6
0
        private static void SetPropertyValue(PropertyInfo property, object target, object value)
        {
            _log.DebugFormat("SetPropertyValue called; Target object type={0}, property={1}, value='{2}'.", target.GetType().FullName, property.Name, value);

            try
            {
                if (property.PropertyType == value.GetType())
                {
                    property.SetValue(target, value, null);
                }
                else
                {
                    object newValue = CreateRawObject(property.PropertyType, new Type[] { value.GetType() }, value);

                    property.SetValue(target, newValue, null);
                }
            }
            catch (ArgumentException ex)
            {
                throw ThrowHelper.New <InternalErrorException>(ExceptionContext, ex, InternalErrors.UnableToSetPropertyValueOnObject,
                                                               property.Name, value, target.GetType().FullName);
            }
        }
示例#7
0
        private object CreateObject(ElementDefinition definition, XElement sourceElement, object parentObject)
        {
            _log.DebugFormat("CreateObject(ElementDefinition, XElement) called; ElementName='{0}.'", definition.ElementName);

            Type[]   constructorParameterTypes;
            object[] constructorParameterValues;

            GetConstructorParameters(definition, sourceElement, parentObject, out constructorParameterTypes, out constructorParameterValues);

            object newObject = CreateRawObject(definition.TargetType, constructorParameterTypes, constructorParameterValues);

            if (definition.CacheElementValueInstruction != null)
            {
                _elementValueCache[definition.CacheElementValueInstruction.CacheKey] = newObject;
            }

            IEnumerable <XAttribute> attributes = sourceElement.Attributes();

            try
            {
                ProcessAttributes(definition.TargetType, definition.Attributes, attributes, newObject);
            }
            catch (Atdl4netException ex)
            {
                throw ThrowHelper.Rethrow(this, ex, new ExceptionInfo(sourceElement), ErrorMessages.GeneralElementProcessingError, string.Empty);
            }

            ProcessChildren(definition, sourceElement, newObject);

            if (newObject.GetType() == _notifyCreationOfType)
            {
                NotifyClassDeserialized(_notifyCreationOfType, newObject);
            }

            return(newObject);
        }
示例#8
0
        private static object ReadAttribute(IEnumerable <XAttribute> attributes, XName attributeName, Type type)
        {
            _log.DebugFormat("ReadAttribute(IEnumerable<XAttribute>, XName, Type) called; Attribute name='{0}'", attributeName);

            XAttribute attribute = attributes.FirstOrDefault(a => a.Name == attributeName);

            if (attribute == null)
            {
                return(null);
            }

            // NB Most simple enums are dealt with in the other overload of ReadAttribute.
            if (type.IsEnum)
            {
                try
                {
                    return(Enum.Parse(type, attribute.Value));
                }
                catch (ArgumentException ex)
                {
                    throw ThrowHelper.New <InvalidFieldValueException>(ExceptionContext, ex, ErrorMessages.InvalidValueEnumParseFailure, attribute.Value, type.Name);
                }
            }
            else
            {
                try
                {
                    return(ValueConverter.ConvertTo(attribute.Value, type));
                }
                catch (FormatException ex)
                {
                    throw ThrowHelper.New <InvalidFieldValueException>(ExceptionContext, ex, ErrorMessages.DataConversionError2,
                                                                       attribute.Value, type.Name, attributeName.LocalName);
                }
            }
        }
示例#9
0
        private void ProcessChildren(ElementDefinition definition, XElement sourceElement, object target)
        {
            _log.DebugFormat("ProcessChildren called; ElementName='{0}'", definition.ElementName);

            // We have to reflect the target type as we can't rely on the Definition to contain it (e.g. MultiTypeElementDefinition).
            Type targetType = target.GetType();

            foreach (ChildElementDefinition childDefinition in definition.ChildElements)
            {
                bool isRecursiveDefinition = childDefinition.ElementDefinition is RecursiveTypeElementDefinition;
                bool hasContainerElement   = !isRecursiveDefinition && childDefinition.ContainerElementName != null;

                IEnumerable <XElement> matchingChildElements;

                ElementDefinition targetDefinition = isRecursiveDefinition ? definition : childDefinition.ElementDefinition;

                if (hasContainerElement)
                {
                    XElement containerElement = (from e in sourceElement.Elements(childDefinition.ContainerElementName) select e).FirstOrDefault();

                    if (containerElement == null)
                    {
                        return;
                    }

                    matchingChildElements = from e in containerElement.Elements(childDefinition.ElementDefinition.ElementName) select e;
                }
                else
                {
                    matchingChildElements = from e in sourceElement.Elements(targetDefinition.ElementName) select e;
                }

                foreach (XElement childElement in matchingChildElements)
                {
                    object childObject;

                    if (targetDefinition is GenericTypeElementDefinition)
                    {
                        childObject = CreateObject(targetDefinition as GenericTypeElementDefinition, childElement, target);
                    }
                    else if (targetDefinition is MultiTypeElementDefinition)
                    {
                        childObject = CreateObject(targetDefinition as MultiTypeElementDefinition, childElement, target);
                    }
                    else
                    {
                        childObject = CreateObject(targetDefinition, childElement, target);
                    }

                    PropertyInfo property = targetType.GetProperty(childDefinition.ContainerProperty);

                    if (property == null)
                    {
                        throw ThrowHelper.New <InternalErrorException>(this, InternalErrors.PropertyNotFoundOnObjectInternal,
                                                                       childDefinition.ContainerProperty, targetType.FullName);
                    }
                    try
                    {
                        // For the case of MultiTypeElementDefinition we must use the reflected type
                        ProcessChildProperty(childDefinition, property, targetDefinition.TargetType ?? childObject.GetType(), target, childObject);
                    }
                    catch (Atdl4netException ex)
                    {
                        throw ThrowHelper.Rethrow(this, ex, new ExceptionInfo(childElement), ErrorMessages.GeneralElementProcessingError,
                                                  definition.ElementName.LocalName);
                    }
                    catch (ArgumentException ex)
                    {
                        throw ThrowHelper.New <Atdl4netException>(this, ex, new ExceptionInfo(childElement), ErrorMessages.GeneralElementProcessingError,
                                                                  definition.ElementName.LocalName, ex.Message);
                    }
                }
            }
        }
示例#10
0
        private void ProcessAttributes(Type targetType, ElementAttribute[] attributeDefinitions, IEnumerable <XAttribute> attributes, object target)
        {
            _log.DebugFormat("ProcessAttributes called; Target type={0}.", targetType.FullName);

            foreach (ElementAttribute attrDefn in attributeDefinitions)
            {
                object value = null;

                if (attrDefn.Type.IsEnum && attrDefn.EnumValues != null)
                {
                    value = ReadAttribute(attributes, attrDefn.XmlName, attrDefn.Type, attrDefn.EnumValues);
                }
                else
                {
                    value = ReadAttribute(attributes, attrDefn.XmlName, attrDefn.Type);
                }

                if (attrDefn.Required == Required.Mandatory && value == null)
                {
                    throw ThrowHelper.New <MissingMandatoryValueException>(this, ErrorMessages.MissingMandatoryAttribute,
                                                                           attrDefn.XmlName.LocalName, targetType.Name);
                }

                if (value == null)
                {
                    continue;
                }

                // Process indirect properties (only one level of indirect is supported).
                if (attrDefn.Property.Contains("."))
                {
                    string[] names = attrDefn.Property.Split(new char[] { '.' });

                    if (names.Length != 2)
                    {
                        throw ThrowHelper.New <InternalErrorException>(this, InternalErrors.InvalidPropertyIndirection, attrDefn.Property);
                    }

                    PropertyInfo outerProperty = targetType.GetProperty(names[0]);

                    if (outerProperty == null)
                    {
                        throw ThrowHelper.New <InternalErrorException>(this, InternalErrors.PropertyNotFoundOnObjectInternal, names[0], targetType.FullName);
                    }

                    object innerObject = outerProperty.GetValue(target, null);

                    if (innerObject == null)
                    {
                        throw ThrowHelper.New <InternalErrorException>(this, InternalErrors.UnableToRetrievePropertyValueOnObject, attrDefn.Property, targetType.FullName);
                    }

                    PropertyInfo property = outerProperty.PropertyType.GetProperty(names[1]);

                    if (property == null)
                    {
                        throw ThrowHelper.New <InvalidPropertyOnObjectException>(this, ErrorMessages.PropertyNotFoundOnObject, attrDefn.Property, targetType.Name);
                    }

                    SetPropertyValue(property, innerObject, value);
                }
                else
                {
                    PropertyInfo property = targetType.GetProperty(attrDefn.Property);

                    if (property == null)
                    {
                        throw ThrowHelper.New <InvalidPropertyOnObjectException>(this, ErrorMessages.PropertyNotFoundOnObject, attrDefn.Property, targetType.Name);
                    }

                    SetPropertyValue(property, target, value);
                }
            }
        }
示例#11
0
        private object CreateObject(MultiTypeElementDefinition multiTypeDefinition, XElement sourceElement, object parentObject)
        {
            _log.DebugFormat("CreateObject(MultiTypeElementDefinition, XElement) called; ElementName='{0}'.", multiTypeDefinition.ElementName);

            object[] constructorParameterValues;
            Type[]   constructorParameterTypes;

            GetConstructorParameters(multiTypeDefinition, sourceElement, parentObject, out constructorParameterTypes, out constructorParameterValues);

            string typeName = ReadAttribute(sourceElement.Attributes(), multiTypeDefinition.AttributeForType, typeof(string)) as string;

            if (string.IsNullOrEmpty(typeName))
            {
                throw ThrowHelper.New <MissingMandatoryValueException>(this, new ExceptionInfo(sourceElement), ErrorMessages.MissingMandatoryAttribute,
                                                                       multiTypeDefinition.AttributeForType.LocalName, multiTypeDefinition.ElementName.LocalName);
            }

            // If the value for the typename is in an XML namespace, remove it.
            if (typeName.Contains(':') && typeName.IndexOf(':') < typeName.Length - 1)
            {
                typeName = typeName.Substring(typeName.IndexOf(':') + 1);
            }

            Type targetType;

            if (string.IsNullOrEmpty(multiTypeDefinition.TypeNamespace))
            {
                targetType = Type.GetType(typeName);
            }
            else
            {
                targetType = Type.GetType(string.Format("{0}.{1}", multiTypeDefinition.TypeNamespace, typeName));
            }

            if (targetType == null)
            {
                throw ThrowHelper.New <InvalidFieldValueException>(this, new ExceptionInfo(sourceElement), ErrorMessages.UnrecognisedTypeError, typeName,
                                                                   multiTypeDefinition.AttributeForType.LocalName, multiTypeDefinition.ElementName.LocalName);
            }

            object newObject = CreateRawObject(targetType, constructorParameterTypes, constructorParameterValues);

            IEnumerable <XAttribute> attributes = sourceElement.Attributes();

            try
            {
                ProcessAttributes(newObject.GetType(), multiTypeDefinition.Attributes, attributes, newObject);
                ProcessAttributes(newObject.GetType(), multiTypeDefinition.TypeToAttributesMap[targetType], attributes, newObject);
            }
            catch (Atdl4netException ex)
            {
                throw ThrowHelper.Rethrow(this, ex, new ExceptionInfo(sourceElement), ErrorMessages.GeneralElementProcessingError, string.Empty);
            }

            ProcessChildren(multiTypeDefinition, sourceElement, newObject);

            if (newObject.GetType() == _notifyCreationOfType)
            {
                NotifyClassDeserialized(_notifyCreationOfType, newObject);
            }

            return(newObject);
        }