internal void Serialize(ClassMapping mapping, object instance, bool summary, SerializationMode mode = SerializationMode.AllMembers)
        {
            if (mapping == null) throw Error.ArgumentNull("mapping");

            _current.WriteStartComplexContent();

            // Emit members that need xml /attributes/ first (to facilitate stream writer API)
            foreach (var prop in mapping.PropertyMappings.Where(pm => pm.SerializationHint == XmlSerializationHint.Attribute))
                if(!summary || prop.InSummary) write(mapping, instance, summary, prop, mode);

            // Then emit the rest
            foreach (var prop in mapping.PropertyMappings.Where(pm => pm.SerializationHint != XmlSerializationHint.Attribute))
                if (!summary || prop.InSummary) write(mapping, instance, summary, prop, mode);

            _current.WriteEndComplexContent();
        }
Example #2
0
        private void write(ClassMapping mapping, object instance, bool summary, PropertyMapping prop, SerializationMode mode)
        {
            // Check whether we are asked to just serialize the value element (Value members of primitive Fhir datatypes)
            // or only the other members (Extension, Id etc in primitive Fhir datatypes)
            // Default is all
            if (mode == SerializationMode.ValueElement && !prop.RepresentsValueElement) return;
            if (mode == SerializationMode.NonValueElements && prop.RepresentsValueElement) return;

            var value = prop.GetValue(instance);
            var isEmptyArray = (value as IList) != null && ((IList)value).Count == 0;

         //   Message.Info("Handling member {0}.{1}", mapping.Name, prop.Name);

            if (value != null && !isEmptyArray)
            {
                string memberName = prop.Name;

                // For Choice properties, determine the actual name of the element
                // by appending its type to the base property name (i.e. deceasedBoolean, deceasedDate)
                if (prop.Choice == ChoiceType.DatatypeChoice)
                {
                    memberName = determineElementMemberName(prop.Name, GetSerializationTypeForDataTypeChoiceElements(prop, value));
                }

                _writer.WriteStartProperty(memberName);
               
                var writer = new DispatchingWriter(_writer);

                // Now, if our writer does not use dual properties for primitive values + rest (xml),
                // or this is a complex property without value element, serialize data normally
                if(!_writer.HasValueElementSupport || !serializedIntoTwoProperties(prop,value))
                    writer.Serialize(prop, value, summary, SerializationMode.AllMembers);
                else
                {
                    // else split up between two properties, name and _name
                    writer.Serialize(prop,value, summary, SerializationMode.ValueElement);
                    _writer.WriteEndProperty();
                    _writer.WriteStartProperty("_" + memberName);
                    writer.Serialize(prop, value, summary, SerializationMode.NonValueElements);
                }

                _writer.WriteEndProperty();
            }
        }
        internal object Deserialize(ClassMapping mapping, object existing=null)
        {
            if (mapping == null) throw Error.ArgumentNull("mapping");

            if (existing != null)
            {
                if (mapping.NativeType != existing.GetType())
                    throw Error.Argument("existing", "Existing instance is of type {0}, but type parameter indicates data type is a {1}", existing.GetType().Name, mapping.NativeType.Name);
            }
            else
            {
                var fac = new DefaultModelFactory();
                existing = fac.Create(mapping.NativeType);
            }

            IEnumerable<Tuple<string, IFhirReader>> members = null;

            if (_current.CurrentToken == TokenType.Object)
            {
                members = _current.GetMembers();
            }
            else if(_current.IsPrimitive())
            {
                // Ok, we expected a complex type, but we found a primitive instead. This may happen
                // in Json where the value property and the other elements are separately put into
                // member and _member. In this case, we will parse the primitive into the Value property
                // of the complex type
                if (!mapping.HasPrimitiveValueMember)
                    throw Error.Format("Complex object does not have a value property, yet the reader is at a primitive", _current);

                // Simulate this as actually receiving a member "Value" in a normal complex object,
                // and resume normally
                var valueMember = Tuple.Create(mapping.PrimitiveValueProperty.Name, _current);
                members = new List<Tuple<string, IFhirReader>> { valueMember };
            }
            else
                throw Error.Format("Trying to read a complex object, but reader is not at the start of an object or primitive", _current);

            read(mapping, members, existing);

            return existing;

        }
        private void read(ClassMapping mapping, IEnumerable<Tuple<string,IFhirReader>> members, object existing)
        {
            //bool hasMember;

            foreach (var memberData in members)
            {
                //hasMember = true;
                var memberName = memberData.Item1;  // tuple: first is name of member

                // Find a property on the instance that matches the element found in the data
                // NB: This function knows how to handle suffixed names (e.g. xxxxBoolean) (for choice types).
                var mappedProperty = mapping.FindMappedElementByName(memberName);

                if (mappedProperty != null)
                {
                 //   Message.Info("Handling member {0}.{1}", mapping.Name, memberName);

                    object value = null;

                    // For primitive members we can save time by net calling the getter
                    if (!mappedProperty.IsPrimitive)
                        value = mappedProperty.GetValue(existing);
                   
                    var reader = new DispatchingReader(memberData.Item2);
                    value = reader.Deserialize(mappedProperty, memberName, value);

                    mappedProperty.SetValue(existing, value);
                }
                else
                {
                    if (SerializationConfig.AcceptUnknownMembers == false)
                        throw Error.Format(Messages.DeserializeUnknownMember, _current, memberName);
                    else
                        Message.Info("Skipping unknown member " + memberName);
                }
            }

            // Not sure if the reader needs to verify this. Certainly, I want to accept empty elements for the
            // pseudo-resource TagList (no tags) and probably others.
            //if (!hasMember)
            //    throw Error.Format("Fhir serialization does not allow nor support empty elements");
        }
Example #5
0
        private void read(ClassMapping mapping, IEnumerable<Tuple<string,IFhirReader>> members, Base existing)
        {
            //bool hasMember;

            foreach (var memberData in members)
            {
                //hasMember = true;
                var memberName = memberData.Item1;  // tuple: first is name of member
             
                // Find a property on the instance that matches the element found in the data
                // NB: This function knows how to handle suffixed names (e.g. xxxxBoolean) (for choice types).
                var mappedProperty = mapping.FindMappedElementByName(memberName);

                if (mappedProperty != null)
                {
                    //   Message.Info("Handling member {0}.{1}", mapping.Name, memberName);

                    object value = null;

                    // For primitive members we can save time by not calling the getter
                    if (!mappedProperty.IsPrimitive)
                        value = mappedProperty.GetValue(existing);

                    var reader = new DispatchingReader(memberData.Item2);
                    value = reader.Deserialize(mappedProperty, memberName, value);

                    mappedProperty.SetValue(existing, value);
                }
                else
                {
                    if (SerializationConfig.AcceptUnknownMembers == false)
                        throw Error.Format("Encountered unknown member '{0}' while de-serializing", _current, memberName);
                    else
                        Message.Info("Skipping unknown member " + memberName);
                }
            }

        }
Example #6
0
        internal Base Deserialize(ClassMapping mapping, Base existing=null)
        {
            if (mapping == null) throw Error.ArgumentNull("mapping");

            if (existing == null)
            {
                var fac = new DefaultModelFactory();
                existing = (Base)fac.Create(mapping.NativeType);
            }
            else
            {
                if (mapping.NativeType != existing.GetType())
                    throw Error.Argument("existing", "Existing instance is of type {0}, but data indicates resource is a {1}", existing.GetType().Name, mapping.NativeType.Name);
            }

            IEnumerable<Tuple<string, IFhirReader>> members = null;

            members = _current.GetMembers();
            read(mapping, members, existing);

            return existing;

        }
Example #7
0
        public static ClassMapping Create(Type type)
        {
           // checkMutualExclusiveAttributes(type);

            var result = new ClassMapping();
            result.NativeType = type;

            if (IsMappableType(type))
            {
                result.Name = collectTypeName(type);
                result.Profile = getProfile(type);
                result.IsResource = IsFhirResource(type);

                if (!result.IsResource && !String.IsNullOrEmpty(result.Profile))
                    throw Error.Argument("type", "Type {0} is not a resource, so its FhirType attribute may not specify a profile", type.Name);

                inspectProperties(result);

                return result;
            }
            else
                throw Error.Argument("type", "Type {0} is not marked as a Fhir Resource or datatype using [FhirType]", type.Name);
        }
Example #8
0
        /// <summary>
        /// Enumerate this class' properties using reflection, create PropertyMappings
        /// for them and add them to the PropertyMappings.
        /// </summary>
        private static void inspectProperties(ClassMapping me)
        {
            foreach (var property in ReflectionHelper.FindPublicProperties(me.NativeType))
            {
                // Skip properties that are marked as NotMapped
                if (ReflectionHelper.GetAttribute<NotMappedAttribute>(property) != null) continue;

                var propMapping = PropertyMapping.Create(property);      

                me._propMappings.Add(propMapping.Name.ToUpperInvariant(), propMapping);

                // Keep a pointer to this property if this is a primitive value element ("Value" in primitive types)
                if (propMapping.RepresentsValueElement)
                    me.PrimitiveValueProperty = propMapping;
            }

            me._orderedMappings = me._propMappings.Values.OrderBy(prop => prop.Order).ToList();
        }
        public void Import(Assembly assembly)
        {
            if (assembly == null)
            {
                throw Error.ArgumentNull("assembly");
            }

#if PORTABLE45
            if (assembly.GetCustomAttribute <NotMappedAttribute>() != null)
            {
                return;
            }
#else
            if (Attribute.GetCustomAttribute(assembly, typeof(NotMappedAttribute)) != null)
            {
                return;
            }
#endif

#if PORTABLE45
            IEnumerable <Type> exportedTypes = assembly.ExportedTypes;
#else
            Type[] exportedTypes = assembly.GetExportedTypes();
#endif
            foreach (Type type in exportedTypes)
            {
                // Don't import types marked with [NotMapped]
#if PORTABLE45
                if (type.GetTypeInfo().GetCustomAttribute <NotMappedAttribute>() != null)
                {
                    continue;
                }
#else
                if (Attribute.GetCustomAttribute(type, typeof(NotMappedAttribute)) != null)
                {
                    continue;
                }
#endif

                if (type.IsEnum())
                {
                    // Map an enumeration
                    if (EnumMapping.IsMappableEnum(type))
                    {
                        ImportEnum(type);
                    }
                    else
                    {
                        Message.Info("Skipped enum {0} while doing inspection: not recognized as representing a FHIR enumeration", type.Name);
                    }
                }
                else
                {
                    // Map a Fhir Datatype
                    if (ClassMapping.IsMappableType(type))
                    {
                        ImportType(type);
                    }
                    else
                    {
                        Message.Info("Skipped type {0} while doing inspection: not recognized as representing a FHIR type", type.Name);
                    }
                }
            }
        }