示例#1
0
        /// <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.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();
            }
        }
示例#2
0
        /// <summary>
        /// Detects the payload kind(s).
        /// </summary>
        /// <param name="detectionInfo">Additional information available for the payload kind detection.</param>
        /// <returns>An enumerable of zero, one or more payload kinds that were detected from looking at the payload in the message stream.</returns>
        private IEnumerable <ODataPayloadKind> DetectPayloadKindImplementation(ODataPayloadKindDetectionInfo detectionInfo)
        {
            Debug.Assert(detectionInfo != null, "detectionInfo != null");
            Debug.Assert(this.JsonReader.DisableInStreamErrorDetection, "The in-stream error detection should be disabled for payload kind detection.");

            this.AssertJsonCondition(JsonNodeType.Property, JsonNodeType.EndObject);

            // If we found a metadata URI and parsed it, look at the detected payload kind and return it.
            if (this.MetadataUriParseResult != null)
            {
                // Store the parsed metadata URI on the input context so we can avoid parsing it again.
                detectionInfo.SetPayloadKindDetectionFormatState(new ODataJsonLightPayloadKindDetectionState(this.MetadataUriParseResult));

                return(this.MetadataUriParseResult.DetectedPayloadKinds);
            }

            // Otherwise this is a payload without metadata URI and we have to start sniffing; only odata.error payloads
            // don't have a metadata URI so check for a single 'odata.error' property (ignoring custom annotations).
            ODataError error = null;

            while (this.JsonReader.NodeType == JsonNodeType.Property)
            {
                string propertyName = this.JsonReader.ReadPropertyName();
                if (!ODataJsonLightReaderUtils.IsAnnotationProperty(propertyName))
                {
                    // If we find a non-annotation property, this is not an error payload
                    return(Enumerable.Empty <ODataPayloadKind>());
                }

                string annotatedPropertyName, annotationName;
                if (!ODataJsonLightDeserializer.TryParsePropertyAnnotation(propertyName, out annotatedPropertyName, out annotationName))
                {
                    // Instance annotation; check for odata.error
                    if (ODataJsonLightReaderUtils.IsODataAnnotationName(propertyName))
                    {
                        if (string.CompareOrdinal(ODataAnnotationNames.ODataError, propertyName) == 0)
                        {
                            // If we find multiple errors or an invalid error value, this is not an error payload.
                            if (error != null || !this.JsonReader.StartBufferingAndTryToReadInStreamErrorPropertyValue(out error))
                            {
                                return(Enumerable.Empty <ODataPayloadKind>());
                            }

                            // At this point we successfully read the first odata.error property.
                            // Skip the error value and check whether there are more properties.
                            this.JsonReader.SkipValue();
                        }
                        else
                        {
                            // Any odata.* instance annotations other than odata.error are not allowed for errors.
                            return(Enumerable.Empty <ODataPayloadKind>());
                        }
                    }
                    else
                    {
                        // Skip custom instance annotations
                        this.JsonReader.SkipValue();
                    }
                }
                else
                {
                    // Property annotation; not allowed for errors
                    return(Enumerable.Empty <ODataPayloadKind>());
                }
            }

            // If we got here without finding a metadata URI or an error payload, we don't know what this is.
            if (error == null)
            {
                return(Enumerable.Empty <ODataPayloadKind>());
            }

            return(new ODataPayloadKind[] { ODataPayloadKind.Error });
        }
示例#3
0
        /// <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);
                propertyNameFromReader = propertyNameFromReader ?? 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.Strings.ODataJsonLightDeserializer_AnnotationTargetingInstanceAnnotationWithoutValue(lastPropertyAnnotationNameFound, parsedPropertyName));
                    }

                    return(PropertyParsingResult.PropertyWithoutValue);
                }

                duplicatePropertyNamesChecker.AnnotationCollector.ShouldCollectAnnotation =
                    (this.MessageReaderSettings.UndeclaredPropertyBehaviorKinds
                     == ODataUndeclaredPropertyBehaviorKinds.SupportUndeclaredValueProperty);
                string skippedRawJson = null;
                if (isPropertyAnnotation)
                {
                    duplicatePropertyNamesChecker.AnnotationCollector.TryPeekAndCollectAnnotationRawJson(
                        this.JsonReader, propertyNameFromReader, annotationNameFromReader);

                    // 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, out skippedRawJson))
                    {
                        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, out skippedRawJson))
                {
                    // collect 'odata.<unknown>' annotation:
                    // here we know the original property name contains no '@', but '.' dot
                    Debug.Assert(annotationNameFromReader == null, "annotationNameFromReader == null");
                    duplicatePropertyNamesChecker.AnnotationCollector.TryAddPropertyAnnotationRawJson(
                        "", propertyNameFromReader, skippedRawJson);
                    continue;
                }

                // We are encountering the property name for the first time.
                // Read over the property name.
                this.JsonReader.Read();
                parsedPropertyName = propertyNameFromReader;

                if (ODataJsonLightUtils.IsMetadataReferenceProperty(propertyNameFromReader))
                {
                    return(PropertyParsingResult.MetadataReferenceProperty);
                }

                if (!ODataJsonLightReaderUtils.IsAnnotationProperty(propertyNameFromReader))
                {
                    // Normal property
                    return(PropertyParsingResult.PropertyWithValue);
                }

                // collect 'xxx.yyyy' annotation:
                // here we know the original property name contains no '@', but '.' dot
                Debug.Assert(annotationNameFromReader == null, "annotationNameFromReader == null");
                duplicatePropertyNamesChecker.AnnotationCollector.TryPeekAndCollectAnnotationRawJson(
                    this.JsonReader, "", propertyNameFromReader); // propertyNameFromReader is the annotation name

                // Handle 'odata.XXXXX' annotations
                if (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.Strings.ODataJsonLightDeserializer_AnnotationTargetingInstanceAnnotationWithoutValue(lastPropertyAnnotationNameFound, parsedPropertyName));
                }

                return(PropertyParsingResult.PropertyWithoutValue);
            }

            return(PropertyParsingResult.EndOfObject);
        }