/// <summary> /// Process the current property annotation. /// </summary> /// <param name="annotatedPropertyName">The name being annotated. Can be a property or an instance annotation.</param> /// <param name="annotationName">The annotation targeting the <paramref name="annotatedPropertyName"/>.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker.</param> /// <param name="readPropertyAnnotationValue">Callback to read the property annotation value.</param> private void ProcessPropertyAnnotation(string annotatedPropertyName, string annotationName, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func <string, object> readPropertyAnnotationValue) { // We don't currently support annotation targeting an instance annotation except for the @odata.type property annotation. if (ODataJsonLightReaderUtils.IsAnnotationProperty(annotatedPropertyName) && string.CompareOrdinal(annotationName, ODataAnnotationNames.ODataType) != 0) { throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_OnlyODataTypeAnnotationCanTargetInstanceAnnotation(annotationName, annotatedPropertyName, ODataAnnotationNames.ODataType)); } // Read over the property name. this.JsonReader.Read(); if (ODataJsonLightReaderUtils.IsODataAnnotationName(annotationName)) { // OData annotations are read. duplicatePropertyNamesChecker.AddODataPropertyAnnotation(annotatedPropertyName, annotationName, readPropertyAnnotationValue(annotationName)); } else { if (this.ShouldSkipCustomInstanceAnnotation(annotationName) || (this is ODataJsonLightErrorDeserializer && this.MessageReaderSettings.ShouldIncludeAnnotation == null)) { // Make sure there's no duplicated instance annotation name even though we are skipping over it. duplicatePropertyNamesChecker.AddCustomPropertyAnnotation(annotatedPropertyName, annotationName); this.JsonReader.SkipValue(); } else { Debug.Assert(ReadPropertyCustomAnnotationValue != null, "readPropertyCustomAnnotationValue != null"); duplicatePropertyNamesChecker.AddCustomPropertyAnnotation(annotatedPropertyName, annotationName, ReadPropertyCustomAnnotationValue(duplicatePropertyNamesChecker, annotationName)); } } }
/// <summary> /// Process the current property annotation. /// </summary> /// <param name="annotatedPropertyName">The name being annotated. Can be a property or an instance annotation.</param> /// <param name="annotationName">The annotation targeting the <paramref name="annotatedPropertyName"/>.</param> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker.</param> /// <param name="readPropertyAnnotationValue">Callback to read the property annotation value.</param> private void ProcessPropertyAnnotation(string annotatedPropertyName, string annotationName, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func <string, object> readPropertyAnnotationValue) { // We don't currently support annotation targeting an instance annotation except for the @odata.type property annotation. if (ODataJsonLightReaderUtils.IsAnnotationProperty(annotatedPropertyName) && string.CompareOrdinal(annotationName, ODataAnnotationNames.ODataType) != 0) { throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_OnlyODataTypeAnnotationCanTargetInstanceAnnotation(annotationName, annotatedPropertyName, ODataAnnotationNames.ODataType)); } // Read over the property name. this.JsonReader.Read(); if (ODataJsonLightReaderUtils.IsODataAnnotationName(annotationName)) { // OData annotations are read. duplicatePropertyNamesChecker.AddODataPropertyAnnotation(annotatedPropertyName, annotationName, readPropertyAnnotationValue(annotationName)); } else { // All other property annotations are ignored. duplicatePropertyNamesChecker.AddCustomPropertyAnnotation(annotatedPropertyName, annotationName); this.JsonReader.SkipValue(); } }
/// <summary> /// Parses JSON object property starting with the current position of the JSON reader. /// </summary> /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use, it will also store the property annotations found.</param> /// <param name="readPropertyAnnotationValue">Function called to read property annotation value.</param> /// <param name="parsedPropertyName">The name of the property or instance annotation found.</param> /// <returns> /// PropertyWithValue - a property with value was found. The <paramref name="parsedPropertyName"/> contains the name of the property. /// The reader is positioned on the property value. /// PropertyWithoutValue - a property without a value was found. The <paramref name="parsedPropertyName"/> contains the name of the property. /// The reader is positioned on the node after property annotations (so either a property or end of object). /// ODataInstanceAnnotation - an odata instance annotation was found. The <paramref name="parsedPropertyName"/> contains the name of the annotation. /// The reader is positioned on the value of the annotation. /// CustomInstanceAnnotation - a custom instance annotation was found. The <paramref name="parsedPropertyName"/> contains the name of the annotation. /// The reader is positioned on the value of the annotation. /// MetadataReferenceProperty - a property which is a reference into the metadata was found. /// The reader is positioned on the value of the property. /// EndOfObject - end of the object scope was reached and no properties are to be reported. The <paramref name="parsedPropertyName"/> is null. /// This can only happen if there's a property annotation which is ignored (for example custom one) at the end of the object. /// </returns> private PropertyParsingResult ParseProperty( DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, Func <string, object> readPropertyAnnotationValue, out string parsedPropertyName) { Debug.Assert(duplicatePropertyNamesChecker != null, "duplicatePropertyNamesChecker != null"); Debug.Assert(readPropertyAnnotationValue != null, "readPropertyAnnotationValue != null"); string lastPropertyAnnotationNameFound = null; parsedPropertyName = null; while (this.JsonReader.NodeType == JsonNodeType.Property) { string nameFromReader = this.JsonReader.GetPropertyName(); string propertyNameFromReader, annotationNameFromReader; bool isPropertyAnnotation = TryParsePropertyAnnotation(nameFromReader, out propertyNameFromReader, out annotationNameFromReader); bool isInstanceAnnotation = false; if (!isPropertyAnnotation) { isInstanceAnnotation = IsInstanceAnnotation(nameFromReader); propertyNameFromReader = isInstanceAnnotation ? nameFromReader.Substring(1) : nameFromReader; } // If parsedPropertyName is set and is different from the property name the reader is currently on, // we have parsed a property annotation for a different property than the one at the current position. if (parsedPropertyName != null && string.CompareOrdinal(parsedPropertyName, propertyNameFromReader) != 0) { if (ODataJsonLightReaderUtils.IsAnnotationProperty(parsedPropertyName)) { throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_AnnotationTargetingInstanceAnnotationWithoutValue(lastPropertyAnnotationNameFound, parsedPropertyName)); } return(PropertyParsingResult.PropertyWithoutValue); } if (isPropertyAnnotation) { // If this is a unknown odata annotation targeting a property, we skip over it. See remark on the method SkippedOverUnknownODataAnnotation() for detailed explaination. // Note that we don't skip over unknown odata annotations targeting another annotation. We don't allow annotations (except odata.type) targeting other annotations, // so this.ProcessPropertyAnnotation() will test and fail for that case. if (!ODataJsonLightReaderUtils.IsAnnotationProperty(propertyNameFromReader) && this.SkippedOverUnknownODataAnnotation(annotationNameFromReader)) { continue; } // We have another property annotation for the same property we parsed. parsedPropertyName = propertyNameFromReader; lastPropertyAnnotationNameFound = annotationNameFromReader; this.ProcessPropertyAnnotation(propertyNameFromReader, annotationNameFromReader, duplicatePropertyNamesChecker, readPropertyAnnotationValue); continue; } // If this is a unknown odata annotation, skip over it. See remark on the method SkippedOverUnknownODataAnnotation() for detailed explaination. if (this.SkippedOverUnknownODataAnnotation(propertyNameFromReader)) { continue; } // We are encountering the property name for the first time. // Read over the property name. this.JsonReader.Read(); parsedPropertyName = propertyNameFromReader; if (!isInstanceAnnotation && ODataJsonLightUtils.IsMetadataReferenceProperty(propertyNameFromReader)) { return(PropertyParsingResult.MetadataReferenceProperty); } if (!isInstanceAnnotation && !ODataJsonLightReaderUtils.IsAnnotationProperty(propertyNameFromReader)) { // Normal property return(PropertyParsingResult.PropertyWithValue); } // Handle 'odata.XXXXX' annotations if (isInstanceAnnotation && ODataJsonLightReaderUtils.IsODataAnnotationName(propertyNameFromReader)) { return(PropertyParsingResult.ODataInstanceAnnotation); } // Handle custom annotations return(PropertyParsingResult.CustomInstanceAnnotation); } this.AssertJsonCondition(JsonNodeType.EndObject); if (parsedPropertyName != null) { if (ODataJsonLightReaderUtils.IsAnnotationProperty(parsedPropertyName)) { throw new ODataException(OData.Core.Strings.ODataJsonLightDeserializer_AnnotationTargetingInstanceAnnotationWithoutValue(lastPropertyAnnotationNameFound, parsedPropertyName)); } return(PropertyParsingResult.PropertyWithoutValue); } return(PropertyParsingResult.EndOfObject); }