public override ODataProperty CreateProperty(object graph, string elementName, ODataSerializerContext writeContext) { if (String.IsNullOrWhiteSpace(elementName)) { throw Error.ArgumentNullOrEmpty("elementName"); } if (writeContext == null) { throw Error.ArgumentNull("writeContext"); } if (graph == null) { return new ODataProperty() { Name = elementName, Value = null }; } else { List<ODataProperty> propertyCollection = new List<ODataProperty>(); foreach (IEdmProperty property in _edmComplexType.ComplexDefinition().Properties()) { IEdmTypeReference propertyType = property.Type; ODataSerializer propertySerializer = SerializerProvider.GetEdmTypeSerializer(propertyType); if (propertySerializer == null) { throw Error.NotSupported("Type {0} is not a serializable type", propertyType.FullName()); } // TODO 453795: [OData]Cleanup reflection code in the ODataFormatter. object propertyValue = graph.GetType().GetProperty(property.Name).GetValue(graph, index: null); propertyCollection.Add(propertySerializer.CreateProperty(propertyValue, property.Name, writeContext)); } string typeName = _edmComplexType.FullName(); ODataComplexValue value = new ODataComplexValue() { Properties = propertyCollection, TypeName = typeName }; // Required to support JSON light full metadata mode. value.SetAnnotation<SerializationTypeNameAnnotation>( new SerializationTypeNameAnnotation { TypeName = typeName }); return new ODataProperty() { Name = elementName, Value = value }; } }
private ODataComplexValue ReadComplexValueImplementation(IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.IncreaseRecursionDepth(); base.JsonReader.ReadStartObject(); ODataComplexValue value2 = new ODataComplexValue { TypeName = (complexValueTypeReference != null) ? complexValueTypeReference.ODataFullName() : payloadTypeName }; if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> sourceList = new List<ODataProperty>(); bool flag = false; while (base.JsonReader.NodeType == JsonNodeType.Property) { string strB = base.JsonReader.ReadPropertyName(); if (string.CompareOrdinal("__metadata", strB) == 0) { if (flag) { throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } flag = true; base.JsonReader.SkipValue(); } else if (!ValidationUtils.IsValidPropertyName(strB)) { base.JsonReader.SkipValue(); } else { ODataProperty property = new ODataProperty { Name = strB }; IEdmProperty property2 = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { property2 = ReaderValidationUtils.ValidateValuePropertyDefined(strB, complexValueTypeReference.ComplexDefinition(), base.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { base.JsonReader.SkipValue(); continue; } ODataNullValueBehaviorKind kind = (base.ReadingResponse || (property2 == null)) ? ODataNullValueBehaviorKind.Default : base.Model.NullValueReadBehaviorKind(property2); object obj2 = this.ReadNonEntityValueImplementation((property2 == null) ? null : property2.Type, null, null, kind == ODataNullValueBehaviorKind.Default); if ((kind != ODataNullValueBehaviorKind.IgnoreValue) || (obj2 != null)) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = obj2; sourceList.Add(property); } } } base.JsonReader.ReadEndObject(); value2.Properties = new ReadOnlyEnumerable<ODataProperty>(sourceList); this.DecreaseRecursionDepth(); return value2; }
/// <summary> /// Reads a complex value. /// </summary> /// <param name="complexValueTypeReference">The expected type reference of the value.</param> /// <param name="payloadTypeName">The type name read from the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the collection value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param> /// <returns>The value of the complex value.</returns> /// <remarks> /// Pre-Condition: Fails if the current node is not a JsonNodeType.StartObject or JsonNodeType.PrimitiveValue (with null value) /// Post-Condition: almost anything - the node after the complex value (after the EndObject) /// </remarks> private ODataComplexValue ReadComplexValueImplementation( IEdmComplexTypeReference complexValueTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker) { this.JsonReader.AssertNotBuffering(); this.IncreaseRecursionDepth(); // Read over the start object this.JsonReader.ReadStartObject(); ODataComplexValue complexValue = new ODataComplexValue(); complexValue.TypeName = complexValueTypeReference != null ? complexValueTypeReference.ODataFullName() : payloadTypeName; if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); bool metadataPropertyFound = false; while (this.JsonReader.NodeType == JsonNodeType.Property) { string propertyName = this.JsonReader.ReadPropertyName(); if (string.CompareOrdinal(JsonConstants.ODataMetadataName, propertyName) == 0) { // __metadata property. if (metadataPropertyFound) { throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_MultipleMetadataPropertiesInComplexValue); } metadataPropertyFound = true; this.JsonReader.SkipValue(); } else { if (!ValidationUtils.IsValidPropertyName(propertyName)) { // We ignore properties with an invalid name since these are extension points for the future. this.JsonReader.SkipValue(); } else { // Any other property is data ODataProperty property = new ODataProperty(); property.Name = propertyName; // Lookup the property in metadata IEdmProperty edmProperty = null; bool ignoreProperty = false; if (complexValueTypeReference != null) { edmProperty = ReaderValidationUtils.ValidateValuePropertyDefined(propertyName, complexValueTypeReference.ComplexDefinition(), this.MessageReaderSettings, out ignoreProperty); } if (ignoreProperty) { this.JsonReader.SkipValue(); } else { ODataNullValueBehaviorKind nullValueReadBehaviorKind = this.ReadingResponse || edmProperty == null ? ODataNullValueBehaviorKind.Default : this.Model.NullValueReadBehaviorKind(edmProperty); // Read the property value object propertyValue = this.ReadNonEntityValueImplementation( edmProperty == null ? null : edmProperty.Type, /*duplicatePropertyNamesChecker*/ null, /*collectionValidator*/ null, nullValueReadBehaviorKind == ODataNullValueBehaviorKind.Default); if (nullValueReadBehaviorKind != ODataNullValueBehaviorKind.IgnoreValue || propertyValue != null) { duplicatePropertyNamesChecker.CheckForDuplicatePropertyNames(property); property.Value = propertyValue; properties.Add(property); } } } } } Debug.Assert(this.JsonReader.NodeType == JsonNodeType.EndObject, "After all the properties of a complex value are read the EndObject node is expected."); this.JsonReader.ReadEndObject(); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.JsonReader.AssertNotBuffering(); this.DecreaseRecursionDepth(); return complexValue; }
internal static void AddTypeNameAnnotationAsNeeded(ODataComplexValue value, ODataMetadataLevel metadataLevel) { // ODataLib normally has the caller decide whether or not to serialize properties by leaving properties // null when values should not be serialized. The TypeName property is different and should always be // provided to ODataLib to enable model validation. A separate annotation is used to decide whether or not // to serialize the type name (a null value prevents serialization). // Note that this annotation should not be used for Atom or JSON verbose formats, as it will interfere with // the correct default behavior for those formats. Contract.Assert(value != null); // Only add an annotation if we want to override ODataLib's default type name serialization behavior. if (ShouldAddTypeNameAnnotation(metadataLevel)) { string typeName; // Provide the type name to serialize (or null to force it not to serialize). if (ShouldSuppressTypeNameSerialization(metadataLevel)) { typeName = null; } else { typeName = value.TypeName; } value.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation { TypeName = typeName }); } }
private ODataComplexValue CreateODataComplexValue(Type complexType, object value, string propertyName, bool isCollectionItem, List<object> visitedComplexTypeObjects) { ClientTypeAnnotation clientTypeAnnotation = ClientEdmModel.GetModel(this.requestInfo.MaxProtocolVersion).GetClientTypeAnnotation(complexType); if (visitedComplexTypeObjects == null) { visitedComplexTypeObjects = new List<object>(); } else if (visitedComplexTypeObjects.Contains(value)) { if (propertyName != null) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Serializer_LoopsNotAllowedInComplexTypes(propertyName)); } throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Serializer_LoopsNotAllowedInNonPropertyComplexTypes(clientTypeAnnotation.ElementTypeName)); } if (value == null) { return null; } visitedComplexTypeObjects.Add(value); ODataComplexValue value2 = new ODataComplexValue(); if (!isCollectionItem) { SerializationTypeNameAnnotation annotation = new SerializationTypeNameAnnotation { TypeName = this.requestInfo.GetServerTypeName(clientTypeAnnotation) }; value2.SetAnnotation<SerializationTypeNameAnnotation>(annotation); } value2.Properties = this.PopulateProperties(clientTypeAnnotation, value, visitedComplexTypeObjects); visitedComplexTypeObjects.Remove(value); return value2; }
internal static void AddTypeNameAnnotationAsNeeded(ODataComplexValue value, ODataMetadataLevel metadataLevel) { Contract.Assert(value != null); if (ShouldAddTypeNameAnnotation(metadataLevel)) { string typeName; if (ShouldSuppressTypeNameSerialization(metadataLevel)) { typeName = null; } else { typeName = value.TypeName; } value.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation { TypeName = typeName }); } }
/// <summary> /// Read a complex value from the reader. /// </summary> /// <param name="complexTypeReference">The type reference of the value to read (or null if no type is available).</param> /// <param name="payloadTypeName">The name of the type specified in the payload.</param> /// <param name="serializationTypeNameAnnotation">The serialization type name for the complex value (possibly null).</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use (cached), or null if new one should be created.</param> /// <param name="epmPresent">Whether any EPM mappings exist.</param> /// <returns>The value read from the payload.</returns> /// <remarks> /// Pre-Condition: XmlNodeType.Element - the element to read the value for. /// XmlNodeType.Attribute - an attribute on the element to read the value for. /// Post-Condition: XmlNodeType.EndElement - the element has been read. /// /// Note that this method will not read null values, those should be handled by the caller already. /// </remarks> private ODataComplexValue ReadComplexValue( IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { this.AssertXmlCondition(XmlNodeType.Element, XmlNodeType.Attribute); this.IncreaseRecursionDepth(); ODataComplexValue complexValue = new ODataComplexValue(); IEdmComplexType complexType = complexTypeReference == null ? null : (IEdmComplexType)complexTypeReference.Definition; // If we have a metadata type for the complex value, use that type name // otherwise use the type name from the payload (if there was any). complexValue.TypeName = complexType == null ? payloadTypeName : complexType.ODataFullName(); if (serializationTypeNameAnnotation != null) { complexValue.SetAnnotation(serializationTypeNameAnnotation); } // Move to the element (so that if we were on an attribute we can test the element for being empty) this.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = this.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); this.ReadPropertiesImplementation(complexType, properties, duplicatePropertyNamesChecker, epmPresent); complexValue.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.AssertXmlCondition(true, XmlNodeType.EndElement); Debug.Assert(complexValue != null, "The method should never return null since it doesn't handle null values."); this.DecreaseRecursionDepth(); return complexValue; }
private ODataComplexValue ReadComplexValue(IEdmComplexTypeReference complexTypeReference, string payloadTypeName, SerializationTypeNameAnnotation serializationTypeNameAnnotation, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, bool epmPresent) { this.IncreaseRecursionDepth(); ODataComplexValue value2 = new ODataComplexValue(); IEdmComplexType type = (complexTypeReference == null) ? null : ((IEdmComplexType) complexTypeReference.Definition); value2.TypeName = (type == null) ? payloadTypeName : type.ODataFullName(); if (serializationTypeNameAnnotation != null) { value2.SetAnnotation<SerializationTypeNameAnnotation>(serializationTypeNameAnnotation); } base.XmlReader.MoveToElement(); if (duplicatePropertyNamesChecker == null) { duplicatePropertyNamesChecker = base.CreateDuplicatePropertyNamesChecker(); } else { duplicatePropertyNamesChecker.Clear(); } List<ODataProperty> properties = new List<ODataProperty>(); this.ReadPropertiesImplementation(type, properties, duplicatePropertyNamesChecker, epmPresent); value2.Properties = new ReadOnlyEnumerable<ODataProperty>(properties); this.DecreaseRecursionDepth(); return value2; }