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(); }
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"); }
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); } } }
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; }
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); }
/// <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); } } } }