internal void WritePrimitiveValue(object value, CollectionWithoutExpectedTypeValidator collectionValidator, IEdmTypeReference expectedTypeReference)
        {
            IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());

            if (collectionValidator != null)
            {
                if (primitiveTypeReference == null)
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
                }
                collectionValidator.ValidateCollectionItem(primitiveTypeReference.FullName(), EdmTypeKind.Primitive);
            }
            if (expectedTypeReference != null)
            {
                ValidationUtils.ValidateIsExpectedPrimitiveType(value, primitiveTypeReference, expectedTypeReference);
            }
            if ((primitiveTypeReference != null) && primitiveTypeReference.IsSpatial())
            {
                string typeName = primitiveTypeReference.FullName();
                PrimitiveConverter.Instance.WriteJson(value, base.JsonWriter, typeName, base.Version);
            }
            else
            {
                base.JsonWriter.WritePrimitiveValue(value, base.Version);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Writes a primitive value.
        /// Uses a registered primitive type converter to write the value if one is registered for the type, otherwise directly writes the value.
        /// </summary>
        /// <param name="value">The value to write.</param>
        /// <param name="expectedTypeReference">The expected type reference of the primitive value.</param>
        public void WritePrimitiveValue(
            object value,
            IEdmTypeReference expectedTypeReference)
        {
            Debug.Assert(value != null, "value != null");

            // Try convert primitive values from their actual CLR types to their underlying CLR types.
            value = this.Model.ConvertToUnderlyingTypeIfUIntValue(value, expectedTypeReference);

            IEdmPrimitiveTypeReference actualTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());
            ODataPayloadValueConverter converter           = this.Model.GetPayloadValueConverter();

            // Skip validation if user has set custom PayloadValueConverter
            if (expectedTypeReference != null && converter.GetType() == typeof(ODataPayloadValueConverter))
            {
                ValidationUtils.ValidateIsExpectedPrimitiveType(value, actualTypeReference, expectedTypeReference, !this.JsonLightOutputContext.MessageWriterSettings.EnableFullValidation);
            }

            value = converter.ConvertToPayloadValue(value, expectedTypeReference);

            if (actualTypeReference != null && actualTypeReference.IsSpatial())
            {
                PrimitiveConverter.Instance.WriteJsonLight(value, this.JsonWriter);
            }
            else
            {
                this.JsonWriter.WritePrimitiveValue(value);
            }
        }
        private static IEdmPrimitiveTypeReference GetPrimitiveTypeReferenceFromTypeAndFacets(Type clrType, List <KeyValuePair <string, object> > annotations)
        {
            IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(clrType);

            if (primitiveTypeReference.IsSpatial())
            {
                primitiveTypeReference = new EdmSpatialTypeReference(primitiveTypeReference.PrimitiveDefinition(), primitiveTypeReference.IsNullable, null);
            }
            return(primitiveTypeReference.ApplyFacetAnnotations(annotations));
        }
Beispiel #4
0
        private object ReadNonEntityValueImplementation(IEdmTypeReference expectedTypeReference, DuplicatePropertyNamesChecker duplicatePropertyNamesChecker, CollectionWithoutExpectedTypeValidator collectionValidator, bool validateNullValue)
        {
            object obj2;
            SerializationTypeNameAnnotation annotation;
            EdmTypeKind  kind;
            JsonNodeType nodeType = base.JsonReader.NodeType;

            if (nodeType == JsonNodeType.StartArray)
            {
                throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType));
            }
            if (this.TryReadNullValue(expectedTypeReference, validateNullValue))
            {
                return(null);
            }
            string            payloadTypeName = this.FindTypeNameInPayload();
            IEdmTypeReference type            = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(EdmTypeKind.None, null, expectedTypeReference, payloadTypeName, base.Model, base.MessageReaderSettings, base.Version, new Func <EdmTypeKind>(this.GetNonEntityValueKind), out kind, out annotation);

            switch (kind)
            {
            case EdmTypeKind.Primitive:
            {
                IEdmPrimitiveTypeReference reference2 = (type == null) ? null : type.AsPrimitive();
                if ((payloadTypeName != null) && !reference2.IsSpatial())
                {
                    throw new ODataException(Microsoft.Data.OData.Strings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName));
                }
                obj2 = this.ReadPrimitiveValueImplementation(reference2, validateNullValue);
                break;
            }

            case EdmTypeKind.Complex:
                obj2 = this.ReadComplexValueImplementation((type == null) ? null : type.AsComplex(), payloadTypeName, annotation, duplicatePropertyNamesChecker);
                break;

            case EdmTypeKind.Collection:
            {
                IEdmCollectionTypeReference collectionValueTypeReference = ValidationUtils.ValidateCollectionType(type);
                obj2 = this.ReadCollectionValueImplementation(collectionValueTypeReference, payloadTypeName, annotation);
                break;
            }

            default:
                throw new ODataException(Microsoft.Data.OData.Strings.General_InternalError(InternalErrorCodes.ODataJsonPropertyAndValueDeserializer_ReadPropertyValue));
            }
            if (collectionValidator != null)
            {
                string collectionItemTypeName = ODataJsonReaderUtils.GetPayloadTypeName(obj2);
                collectionValidator.ValidateCollectionItem(collectionItemTypeName, kind);
            }
            return(obj2);
        }
Beispiel #5
0
        private object ReadPrimitiveValueImplementation(IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue)
        {
            if ((expectedValueTypeReference != null) && expectedValueTypeReference.IsSpatial())
            {
                return(this.ReadSpatialValue(expectedValueTypeReference, validateNullValue));
            }
            object obj2 = base.JsonReader.ReadPrimitiveValue();

            if ((expectedValueTypeReference != null) && !base.MessageReaderSettings.DisablePrimitiveTypeConversion)
            {
                obj2 = ODataJsonReaderUtils.ConvertValue(obj2, expectedValueTypeReference, base.MessageReaderSettings, base.Version, validateNullValue);
            }
            return(obj2);
        }
        /// <summary>
        /// Try and parse spatial type from the json payload.
        /// </summary>
        /// <param name="jsonReader">The JSON reader to read from.</param>
        /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object
        ///     (or the second property if the first one was odata.type).</param>
        /// <param name="inputContext">The input context with all the settings.</param>
        /// <param name="expectedValueTypeReference">Expected edm property type.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="recursionDepth">The recursion depth to start with.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <returns>An instance of the spatial type.</returns>
        internal static ISpatial ReadSpatialValue(
            BufferingJsonReader jsonReader,
            bool insideJsonObjectValue,
            ODataInputContext inputContext,
            IEdmPrimitiveTypeReference expectedValueTypeReference,
            bool validateNullValue,
            int recursionDepth,
            string propertyName)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(jsonReader != null, "jsonReader != null");
            Debug.Assert(inputContext != null, "inputContext != null");
            Debug.Assert(expectedValueTypeReference != null, "expectedValueTypeReference != null");
            Debug.Assert(expectedValueTypeReference.IsSpatial(), "TryParseSpatialType must be called only with spatial types");

            // Note that we made sure that payload type detection will not return spatial for <V3 payloads
            // So the only way we can get a spatial type reference is if it comes from the model,
            // in which case we want to fail for <V3 payloads, since we can't report spatial values from such payloads.
            ODataVersionChecker.CheckSpatialValue(inputContext.Version);

            // Spatial value can be either null constant or a JSON object
            // If it's a null primitive value, report a null value.
            if (!insideJsonObjectValue && TryReadNullValue(jsonReader, inputContext, expectedValueTypeReference, validateNullValue, propertyName))
            {
                return(null);
            }

            System.Spatial.ISpatial spatialValue = null;
            if (insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject)
            {
                IDictionary <string, object>          jsonObject          = ReadObjectValue(jsonReader, insideJsonObjectValue, inputContext, recursionDepth);
                System.Spatial.GeoJsonObjectFormatter jsonObjectFormatter =
                    System.Spatial.SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter();
                if (EdmLibraryExtensions.IsGeographyType(expectedValueTypeReference))
                {
                    spatialValue = jsonObjectFormatter.Read <System.Spatial.Geography>(jsonObject);
                }
                else
                {
                    spatialValue = jsonObjectFormatter.Read <System.Spatial.Geometry>(jsonObject);
                }
            }

            if (spatialValue == null)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderCoreUtils_CannotReadSpatialPropertyValue);
            }

            return(spatialValue);
        }
        /// <summary>
        /// Try and parse spatial type from the json payload.
        /// </summary>
        /// <param name="jsonReader">The JSON reader to read from.</param>
        /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object
        ///     (or the second property if the first one was odata.type).</param>
        /// <param name="inputContext">The input context with all the settings.</param>
        /// <param name="expectedValueTypeReference">Expected edm property type.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="recursionDepth">The recursion depth to start with.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <returns>An instance of the spatial type.</returns>
        internal static async Task <ISpatial> ReadSpatialValueAsync(
            IJsonReaderAsync jsonReader,
            bool insideJsonObjectValue,
            ODataInputContext inputContext,
            IEdmPrimitiveTypeReference expectedValueTypeReference,
            bool validateNullValue,
            int recursionDepth,
            string propertyName)
        {
            Debug.Assert(jsonReader != null, "jsonReader != null");
            Debug.Assert(inputContext != null, "inputContext != null");
            Debug.Assert(expectedValueTypeReference != null, "expectedValueTypeReference != null");
            Debug.Assert(expectedValueTypeReference.IsSpatial(), "TryParseSpatialType must be called only with spatial types");

            // Spatial value can be either null constant or a JSON object
            // If it's a null primitive value, report a null value.
            if (!insideJsonObjectValue &&
                await TryReadNullValueAsync(jsonReader, inputContext, expectedValueTypeReference, validateNullValue, propertyName)
                .ConfigureAwait(false))
            {
                return(null);
            }

            ISpatial spatialValue = null;

            if (insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject)
            {
                Dictionary <string, object> jsonObject = await ReadObjectValueAsync(jsonReader, insideJsonObjectValue, inputContext, recursionDepth)
                                                         .ConfigureAwait(false);

                GeoJsonObjectFormatter jsonObjectFormatter =
                    SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter();
                if (expectedValueTypeReference.IsGeography())
                {
                    spatialValue = jsonObjectFormatter.Read <Geography>(jsonObject);
                }
                else
                {
                    spatialValue = jsonObjectFormatter.Read <Geometry>(jsonObject);
                }
            }

            if (spatialValue == null)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderCoreUtils_CannotReadSpatialPropertyValue);
            }

            return(spatialValue);
        }
        /// <summary>
        /// Try and parse spatial type from the json payload.
        /// </summary>
        /// <param name="jsonReader">The JSON reader to read from.</param>
        /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object 
        ///     (or the second property if the first one was odata.type).</param>
        /// <param name="inputContext">The input context with all the settings.</param>
        /// <param name="expectedValueTypeReference">Expected edm property type.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="recursionDepth">The recursion depth to start with.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <returns>An instance of the spatial type.</returns>
        internal static ISpatial ReadSpatialValue(
            BufferingJsonReader jsonReader,
            bool insideJsonObjectValue,
            ODataInputContext inputContext,
            IEdmPrimitiveTypeReference expectedValueTypeReference,
            bool validateNullValue,
            int recursionDepth,
            string propertyName)
        {
            Debug.Assert(jsonReader != null, "jsonReader != null");
            Debug.Assert(inputContext != null, "inputContext != null");
            Debug.Assert(expectedValueTypeReference != null, "expectedValueTypeReference != null");
            Debug.Assert(expectedValueTypeReference.IsSpatial(), "TryParseSpatialType must be called only with spatial types");

            // Spatial value can be either null constant or a JSON object
            // If it's a null primitive value, report a null value.
            if (!insideJsonObjectValue && TryReadNullValue(jsonReader, inputContext, expectedValueTypeReference, validateNullValue, propertyName))
            {
                return null;
            }

            Microsoft.Spatial.ISpatial spatialValue = null;
            if (insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject)
            {
                IDictionary<string, object> jsonObject = ReadObjectValue(jsonReader, insideJsonObjectValue, inputContext, recursionDepth);
                Microsoft.Spatial.GeoJsonObjectFormatter jsonObjectFormatter =
                    Microsoft.Spatial.SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter();
                if (EdmLibraryExtensions.IsGeographyType(expectedValueTypeReference))
                {
                    spatialValue = jsonObjectFormatter.Read<Microsoft.Spatial.Geography>(jsonObject);
                }
                else
                {
                    spatialValue = jsonObjectFormatter.Read<Microsoft.Spatial.Geometry>(jsonObject);
                }
            }

            if (spatialValue == null)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderCoreUtils_CannotReadSpatialPropertyValue);
            }

            return spatialValue;
        }
        /// <summary>
        /// Try and parse spatial type from the json payload.
        /// </summary>
        /// <param name="jsonReader">The JSON reader to read from.</param>
        /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object
        ///     (or the second property if the first one was odata.type).</param>
        /// <param name="inputContext">The input context with all the settings.</param>
        /// <param name="expectedValueTypeReference">Expected edm property type.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="recursionDepth">The recursion depth to start with.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <returns>An instance of the spatial type.</returns>
        internal static ISpatial ReadSpatialValue(
            BufferingJsonReader jsonReader,
            bool insideJsonObjectValue,
            ODataInputContext inputContext,
            IEdmPrimitiveTypeReference expectedValueTypeReference,
            bool validateNullValue,
            int recursionDepth,
            string propertyName)
        {
            Debug.Assert(jsonReader != null, "jsonReader != null");
            Debug.Assert(inputContext != null, "inputContext != null");
            Debug.Assert(expectedValueTypeReference != null, "expectedValueTypeReference != null");
            Debug.Assert(expectedValueTypeReference.IsSpatial(), "TryParseSpatialType must be called only with spatial types");

            // Spatial value can be either null constant or a JSON object
            // If it's a null primitive value, report a null value.
            if (!insideJsonObjectValue && TryReadNullValue(jsonReader, inputContext, expectedValueTypeReference, validateNullValue, propertyName))
            {
                return(null);
            }

            Microsoft.Spatial.ISpatial spatialValue = null;
            if (insideJsonObjectValue || jsonReader.NodeType == JsonNodeType.StartObject)
            {
                IDictionary <string, object>             jsonObject          = ReadObjectValue(jsonReader, insideJsonObjectValue, inputContext, recursionDepth);
                Microsoft.Spatial.GeoJsonObjectFormatter jsonObjectFormatter =
                    Microsoft.Spatial.SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter();
                if (EdmLibraryExtensions.IsGeographyType(expectedValueTypeReference))
                {
                    spatialValue = jsonObjectFormatter.Read <Microsoft.Spatial.Geography>(jsonObject);
                }
                else
                {
                    spatialValue = jsonObjectFormatter.Read <Microsoft.Spatial.Geometry>(jsonObject);
                }
            }

            if (spatialValue == null)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderCoreUtils_CannotReadSpatialPropertyValue);
            }

            return(spatialValue);
        }
Beispiel #10
0
        /// <summary>
        /// Writes a primitive value.
        /// Uses a registered primitive type converter to write the value if one is registered for the type, otherwise directly writes the value.
        /// </summary>
        /// <param name="value">The value to write.</param>
        /// <param name="expectedTypeReference">The expected type reference of the primitive value.</param>
        public void WritePrimitiveValue(
            object value,
            IEdmTypeReference expectedTypeReference)
        {
            Debug.Assert(value != null, "value != null");

            IEdmPrimitiveTypeReference actualTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());

            if (expectedTypeReference != null)
            {
                ValidationUtils.ValidateIsExpectedPrimitiveType(value, actualTypeReference, expectedTypeReference);
            }

            if (actualTypeReference != null && actualTypeReference.IsSpatial())
            {
                PrimitiveConverter.Instance.WriteJsonLight(value, this.JsonWriter);
            }
            else
            {
                this.JsonWriter.WritePrimitiveValue(value);
            }
        }
Beispiel #11
0
        /// <summary>
        /// Reads a primitive value.
        /// </summary>
        /// <param name="expectedValueTypeReference">The expected type reference of the value.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <returns>The value of the primitive value.</returns>
        /// <remarks>
        /// Pre-Condition:  none - Fails if the current node is not a JsonNodeType.PrimitiveValue
        /// Post-Condition: almost anything - the node after the primitive value.
        ///
        /// Made internal only for testability.
        /// </remarks>
        internal object ReadPrimitiveValue(IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue, string propertyName)
        {
            DebugUtils.CheckNoExternalCallers();
            this.JsonReader.AssertNotBuffering();
            object result;

            if (expectedValueTypeReference != null && expectedValueTypeReference.IsSpatial())
            {
                result = ODataJsonReaderCoreUtils.ReadSpatialValue(
                    this.JsonReader,
                    /*insideJsonObjectValue*/ false,
                    this.VerboseJsonInputContext,
                    expectedValueTypeReference,
                    validateNullValue,
                    this.recursionDepth,
                    propertyName);
            }
            else
            {
                result = this.JsonReader.ReadPrimitiveValue();

                if (expectedValueTypeReference != null && !this.MessageReaderSettings.DisablePrimitiveTypeConversion)
                {
                    result = ODataVerboseJsonReaderUtils.ConvertValue(
                        result,
                        expectedValueTypeReference,
                        this.MessageReaderSettings,
                        this.Version,
                        validateNullValue,
                        propertyName);
                }
            }

            this.JsonReader.AssertNotBuffering();

            return(result);
        }
        /// <summary>
        /// Writes a primitive value.
        /// Uses a registered primitive type converter to write the value if one is registered for the type, otherwise directly writes the value.
        /// </summary>
        /// <param name="value">The value to write.</param>
        /// <param name="collectionValidator">The collection validator instance.</param>
        /// <param name="expectedTypeReference">The expected type reference of the primitive value.</param>
        internal void WritePrimitiveValue(
            object value,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            IEdmTypeReference expectedTypeReference)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(value != null, "value != null");

            IEdmPrimitiveTypeReference actualTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(value.GetType());

            if (collectionValidator != null)
            {
                if (actualTypeReference == null)
                {
                    throw new ODataException(o.Strings.ValidationUtils_UnsupportedPrimitiveType(value.GetType().FullName));
                }

                collectionValidator.ValidateCollectionItem(actualTypeReference.FullName(), EdmTypeKind.Primitive);
            }

            if (expectedTypeReference != null)
            {
                ValidationUtils.ValidateIsExpectedPrimitiveType(value, actualTypeReference, expectedTypeReference);
            }

            if (actualTypeReference != null && actualTypeReference.IsSpatial())
            {
                // For spatial types, we will always write the type name. This is consistent with complex types.
                string typeName = actualTypeReference.FullName();
                PrimitiveConverter.Instance.WriteJson(value, this.JsonWriter, typeName, this.Version);
            }
            else
            {
                this.JsonWriter.WritePrimitiveValue(value, this.Version);
            }
        }
 private object ReadPrimitiveValueImplementation(IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue)
 {
     if ((expectedValueTypeReference != null) && expectedValueTypeReference.IsSpatial())
     {
         return this.ReadSpatialValue(expectedValueTypeReference, validateNullValue);
     }
     object obj2 = base.JsonReader.ReadPrimitiveValue();
     if ((expectedValueTypeReference != null) && !base.MessageReaderSettings.DisablePrimitiveTypeConversion)
     {
         obj2 = ODataJsonReaderUtils.ConvertValue(obj2, expectedValueTypeReference, base.MessageReaderSettings, base.Version, validateNullValue);
     }
     return obj2;
 }
Beispiel #14
0
        /// <summary>
        /// Reads a primitive, complex or collection value.
        /// </summary>
        /// <param name="expectedTypeReference">The expected type reference of the property value.</param>
        /// <param name="duplicatePropertyNamesChecker">The duplicate property names checker to use - if null the method should create a new one if necessary.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable.</param>
        /// <returns>The value of the property read.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.PrimitiveValue   - the value of the property is a primitive value
        ///                 JsonNodeType.StartObject      - the value of the property is an object
        ///                 JsonNodeType.StartArray       - the value of the property is an array - method will fail in this case.
        /// Post-Condition: almost anything - the node after the property value.
        ///
        /// Returns the value of the property read, which can be one of:
        /// - null
        /// - primitive value
        /// - <see cref="ODataComplexValue"/>
        /// - <see cref="ODataCollectionValue"/>
        /// </remarks>
        private object ReadNonEntityValueImplementation(
            IEdmTypeReference expectedTypeReference,
            DuplicatePropertyNamesChecker duplicatePropertyNamesChecker,
            CollectionWithoutExpectedTypeValidator collectionValidator,
            bool validateNullValue,
            string propertyName)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(
                this.JsonReader.NodeType == JsonNodeType.PrimitiveValue || this.JsonReader.NodeType == JsonNodeType.StartObject || this.JsonReader.NodeType == JsonNodeType.StartArray,
                "Pre-Condition: expected JsonNodeType.PrimitiveValue or JsonNodeType.StartObject or JsonNodeType.StartArray");
            Debug.Assert(
                expectedTypeReference == null || !expectedTypeReference.IsODataEntityTypeKind(),
                "Only primitive, complex or collection types can be read by this method.");
            Debug.Assert(
                expectedTypeReference == null || collectionValidator == null,
                "If an expected value type reference is specified, no collection validator must be provided.");
            this.JsonReader.AssertNotBuffering();

            // Property values can be only primitives or objects. No property can have a JSON array value.
            JsonNodeType nodeType = this.JsonReader.NodeType;

            if (nodeType == JsonNodeType.StartArray)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_CannotReadPropertyValue(nodeType));
            }

            // Try to read a null value
            object result;

            if (ODataJsonReaderCoreUtils.TryReadNullValue(
                    this.JsonReader,
                    this.VerboseJsonInputContext,
                    expectedTypeReference,
                    validateNullValue,
                    propertyName))
            {
                result = null;
            }
            else
            {
                // Read the payload type name
                string payloadTypeName = this.FindTypeNameInPayload();

                SerializationTypeNameAnnotation serializationTypeNameAnnotation;
                EdmTypeKind       targetTypeKind;
                IEdmTypeReference targetTypeReference = ReaderValidationUtils.ResolvePayloadTypeNameAndComputeTargetType(
                    EdmTypeKind.None,
                    /*defaultPrimitivePayloadType*/ null,
                    expectedTypeReference,
                    payloadTypeName,
                    this.Model,
                    this.MessageReaderSettings,
                    this.Version,
                    this.GetNonEntityValueKind,
                    out targetTypeKind,
                    out serializationTypeNameAnnotation);

                switch (targetTypeKind)
                {
                case EdmTypeKind.Primitive:
                    Debug.Assert(targetTypeReference == null || targetTypeReference.IsODataPrimitiveTypeKind(), "Expected an OData primitive type.");
                    IEdmPrimitiveTypeReference primitiveTargetTypeReference = targetTypeReference == null ? null : targetTypeReference.AsPrimitive();
                    if (payloadTypeName != null && !primitiveTargetTypeReference.IsSpatial())
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonPropertyAndValueDeserializer_InvalidPrimitiveTypeName(payloadTypeName));
                    }

                    result = this.ReadPrimitiveValue(
                        primitiveTargetTypeReference,
                        validateNullValue,
                        propertyName);
                    break;

                case EdmTypeKind.Complex:
                    Debug.Assert(targetTypeReference == null || targetTypeReference.IsComplex(), "Expected a complex type.");
                    result = this.ReadComplexValueImplementation(
                        targetTypeReference == null ? null : targetTypeReference.AsComplex(),
                        payloadTypeName,
                        serializationTypeNameAnnotation,
                        duplicatePropertyNamesChecker);
                    break;

                case EdmTypeKind.Collection:
                    Debug.Assert(this.Version >= ODataVersion.V3, "Type resolution should already fail if we would decide to read a collection value in V1/V2 payload.");
                    IEdmCollectionTypeReference collectionTypeReference = ValidationUtils.ValidateCollectionType(targetTypeReference);
                    result = this.ReadCollectionValueImplementation(
                        collectionTypeReference,
                        payloadTypeName,
                        serializationTypeNameAnnotation);
                    break;

                default:
                    throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.ODataVerboseJsonPropertyAndValueDeserializer_ReadPropertyValue));
                }

                // If we have no expected type make sure the collection items are of the same kind and specify the same name.
                if (collectionValidator != null)
                {
                    string payloadTypeNameFromResult = ODataVerboseJsonReaderUtils.GetPayloadTypeName(result);
                    Debug.Assert(expectedTypeReference == null, "If a collection validator is specified there must not be an expected value type reference.");
                    collectionValidator.ValidateCollectionItem(payloadTypeNameFromResult, targetTypeKind);
                }
            }

            this.JsonReader.AssertNotBuffering();
            return(result);
        }
        /// <summary>
        /// Try and parse spatial type from the json payload.
        /// </summary>
        /// <param name="expectedValueTypeReference">Expected edm property type.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <returns>An instance of the spatial type.</returns>
        private System.Spatial.ISpatial ReadSpatialValue(IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue)
        {
            Debug.Assert(expectedValueTypeReference != null, "expectedValueTypeReference != null");
            Debug.Assert(expectedValueTypeReference.IsSpatial(), "TryParseSpatialType must be called only with spatial types");

            // Note that we made sure that payload type detection will not return spatial for <V3 payloads
            // So the only way we can get a spatial type reference is if it comes from the model,
            // in which case we want to fail for <V3 payloads, since we can't report spatial values from such payloads.
            ODataVersionChecker.CheckSpatialValue(this.Version);

            // Spatial value can be either null constant or a JSON object
            // If it's a null primitive value, report a null value.
            if (this.TryReadNullValue(expectedValueTypeReference, validateNullValue))
            {
                return null;
            }

            System.Spatial.ISpatial spatialValue = null;
            if (this.JsonReader.NodeType == JsonNodeType.StartObject)
            {
                IDictionary<string, object> jsonObject = this.ReadObjectValue(this.JsonReader);
                System.Spatial.GeoJsonObjectFormatter jsonObjectFormatter = 
                    System.Spatial.SpatialImplementation.CurrentImplementation.CreateGeoJsonObjectFormatter();
                if (EdmLibraryExtensions.IsGeographyType(expectedValueTypeReference))
                {
                    spatialValue = jsonObjectFormatter.Read<System.Spatial.Geography>(jsonObject);
                }
                else
                {
                    spatialValue = jsonObjectFormatter.Read<System.Spatial.Geometry>(jsonObject);
                }
            }

            if (spatialValue == null)
            {
                throw new ODataException(o.Strings.ODataJsonPropertyAndValueDeserializer_CannotReadSpatialPropertyValue);
            }

            return spatialValue;
        }
        /// <summary>
        /// Reads a primitive value.
        /// </summary>
        /// <param name="insideJsonObjectValue">true if the reader is positioned on the first property of the value which is a JSON Object 
        ///     (or the second property if the first one was odata.type).</param>
        /// <param name="expectedValueTypeReference">The expected type reference of the value, or null if none is available.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <param name="propertyName">The name of the property whose value is being read, if applicable (used for error reporting).</param>
        /// <returns>The value of the primitive value.</returns>
        /// <remarks>
        /// Pre-Condition:  insideJsonObjectValue == false -> none - Fails if the current node is not a JsonNodeType.PrimitiveValue
        ///                 insideJsonObjectValue == true -> JsonNodeType.Property or JsonNodeType.EndObject - the first property of the value object,
        ///                     or the second property if first was odata.type, or the end-object.
        /// Post-Condition: almost anything - the node after the primitive value.
        /// </remarks>
        private object ReadPrimitiveValue(bool insideJsonObjectValue, IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue, string propertyName)
        {
            object result;

            if (expectedValueTypeReference != null && expectedValueTypeReference.IsSpatial())
            {
                result = ODataJsonReaderCoreUtils.ReadSpatialValue(
                    this.JsonReader,
                    insideJsonObjectValue,
                    this.JsonLightInputContext,
                    expectedValueTypeReference,
                    validateNullValue,
                    this.recursionDepth,
                    propertyName);
            }
            else
            {
                if (insideJsonObjectValue)
                {
                    // We manually throw JSON exception here to get a nicer error message (we expect primitive value and got object).
                    // Otherwise the ReadPrimitiveValue would fail with something like "expected primitive value but found property/end object" which is rather confusing.
                    throw new ODataException(ODataErrorStrings.JsonReaderExtensions_UnexpectedNodeDetectedWithPropertyName(JsonNodeType.PrimitiveValue, JsonNodeType.StartObject, propertyName));
                }

                result = this.JsonReader.ReadPrimitiveValue();

                if (expectedValueTypeReference != null)
                {
                    if ((expectedValueTypeReference.IsDecimal() || expectedValueTypeReference.IsInt64())
                        && result != null)
                    {
                        if ((result is string) ^ this.JsonReader.IsIeee754Compatible)
                        {
                            throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_ConflictBetweenInputFormatAndParameter(expectedValueTypeReference.FullName()));
                        }
                    }

                    result = ODataJsonLightReaderUtils.ConvertValue(
                        result,
                        expectedValueTypeReference,
                        this.MessageReaderSettings,
                        validateNullValue,
                        propertyName,
                        this.Model.GetPayloadValueConverter());
                }
                else
                {
                    if (result is Decimal)
                    {
                        // convert decimal back to double to follow legacy logic when target type is not specified and IEEE754Compatible=false.
                        // we may lose precision for some range of int64 and decimal.
                        return Convert.ToDouble((Decimal)result);
                    }
                }
            }

            return result;
        }
        /// <summary>
        /// Reads a primitive value.
        /// </summary>
        /// <param name="expectedValueTypeReference">The expected type reference of the value.</param>
        /// <param name="validateNullValue">true to validate null values; otherwise false.</param>
        /// <returns>The value of the primitive value.</returns>
        /// <remarks>
        /// Pre-Condition:  none - Fails if the current node is not a JsonNodeType.PrimitiveValue
        /// Post-Condition: almost anything - the node after the primitive value.
        /// </remarks>
        private object ReadPrimitiveValueImplementation(IEdmPrimitiveTypeReference expectedValueTypeReference, bool validateNullValue)
        {
            this.JsonReader.AssertNotBuffering();
            object result;

            if (expectedValueTypeReference != null && expectedValueTypeReference.IsSpatial())
            {
                result = this.ReadSpatialValue(expectedValueTypeReference, validateNullValue);
            }
            else
            {
                result = this.JsonReader.ReadPrimitiveValue();

                if (expectedValueTypeReference != null && !this.MessageReaderSettings.DisablePrimitiveTypeConversion)
                {
                    result = ODataJsonReaderUtils.ConvertValue(result, expectedValueTypeReference, this.MessageReaderSettings, this.Version, validateNullValue);
                }
            }

            this.JsonReader.AssertNotBuffering();

            return result;
        }