From 0698e38a88b670aa2626c73b105e98f529ee8e55 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Fri, 11 Oct 2024 13:00:48 -0500 Subject: [PATCH 1/9] SpatialPoint Serialization/Deserialization: Fixes spatial point serialization/deserilization bug --- Microsoft.Azure.Cosmos/src/Spatial/Point.cs | 4 +- .../src/Spatial/Position.cs | 16 ++++-- .../ClientTests.cs | 51 ++++++++++++++++++- 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs index 640710f0c0..ace5eee506 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs @@ -65,7 +65,7 @@ public Point(Position position, GeometryParams geometryParams) /// /// This constructor is used only during deserialization. /// - internal Point() + public Point() : base(GeometryType.Point, new GeometryParams()) { } @@ -78,7 +78,7 @@ internal Point() /// [DataMember(Name = "coordinates")] [JsonProperty("coordinates", Required = Required.Always, Order = 1)] - public Position Position { get; private set; } + public Position Position { get; set; } /// /// Determines if this is equal to in the Azure Cosmos DB service. diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs index de44b8895b..72e800b5f4 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs @@ -38,6 +38,14 @@ public Position(double longitude, double latitude) : this(longitude, latitude, null) { } + + /// + /// Initializes a new instance of the class in the Azure Cosmos DB service. + /// + public Position() + : this(0.0d, 0.0d) + { + } /// /// Initializes a new instance of the class in the Azure Cosmos DB service. @@ -55,11 +63,11 @@ public Position(double longitude, double latitude, double? altitude) { if (altitude != null) { - this.Coordinates = new ReadOnlyCollection(new[] { longitude, latitude, altitude.Value }); + this.Coordinates = new List(new[] { longitude, latitude, altitude.Value }); } else { - this.Coordinates = new ReadOnlyCollection(new[] { longitude, latitude }); + this.Coordinates = new List(new[] { longitude, latitude }); } } @@ -76,7 +84,7 @@ public Position(IList coordinates) throw new ArgumentException("coordinates"); } - this.Coordinates = new ReadOnlyCollection(coordinates); + this.Coordinates = new List(coordinates); } /// @@ -86,7 +94,7 @@ public Position(IList coordinates) /// Coordinate values. /// [DataMember(Name = "Coordinates")] - public ReadOnlyCollection Coordinates { get; private set; } + public List Coordinates { get; set; } /// /// Gets longitude in the Azure Cosmos DB service. diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 0600c7be85..0aeef26d51 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -29,6 +29,8 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using Moq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; + using Microsoft.Azure.Cosmos.Spatial; + using System.Text.Json; [TestClass] public class ClientTests @@ -936,7 +938,43 @@ public async Task MultiRegionAccountTest() AccountProperties properties = await cosmosClient.ReadAccountAsync(); Assert.IsNotNull(properties); } - + + [TestMethod] + public async Task ValidateSpatialPointJSONSerialization() + { + string authKey = ConfigurationManager.AppSettings["MasterKey"]; + string endpoint = ConfigurationManager.AppSettings["GatewayEndpoint"]; + + using (CosmosClient cosmosClient = new CosmosClient(endpoint, authKey, + new CosmosClientOptions() + { + UseSystemTextJsonSerializerWithOptions = new JsonSerializerOptions() + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + } + })) + { + + string GUID = Guid.NewGuid().ToString(); + Cosmos.Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync("AzureCosmosSpatialSerialization"); + + Container container = await database.CreateContainerIfNotExistsAsync("spatial-items", "/id"); + SpatialItem inputItem = new SpatialItem() + { + Id = GUID, + Name = "Spatial Point", + Location = new Point(1, 1) + }; + + SpatialItem result = await container.CreateItemAsync(inputItem); + SpatialItem readItem = await container.ReadItemAsync(GUID, new Cosmos.PartitionKey(GUID)); + + Assert.AreEqual(readItem, inputItem); + Assert.AreEqual(result, inputItem); + } + + } + public static IReadOnlyList GetActiveConnections() { string testPid = Process.GetCurrentProcess().Id.ToString(); @@ -1023,4 +1061,15 @@ public bool IsBypassed(Uri host) return false; } } + + internal record SpatialItem + { + [JsonProperty("id")] + public string Id { get; set; } + public string Name { get; set; } + public Point Location { get; set; } + + + } + } From 059ca709bf28d3252cc459e41e52ff7f67f53be6 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Mon, 21 Oct 2024 10:19:00 -0500 Subject: [PATCH 2/9] SpatialPoint Serialization/Deserialization: Fixes spatial point serialization/deserilization bug --- .../STJConverters/PositionSTJJsonConverter.cs | 84 +++++++++++++++++++ Microsoft.Azure.Cosmos/src/Spatial/Point.cs | 17 ++-- .../src/Spatial/Position.cs | 26 +++--- .../src/Spatial/PositionMetadataFields.cs | 19 +++++ 4 files changed, 123 insertions(+), 23 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs new file mode 100644 index 0000000000..ee91780cab --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs @@ -0,0 +1,84 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Documents; + using static System.Text.Json.JsonElement; + + /// + /// Converter used to support System.Text.Json de/serialization of type Position/>. + /// + internal class PositionSTJJsonConverter : JsonConverter + { + public override Position Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + //Position position = new Position(); + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals(PositionMetadataFields.Coordinates)) + { + IList coordinates = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + coordinates.Add(arrayElement.GetDouble()); + } + + return new Position(new ReadOnlyCollection(coordinates)); + + } + + } + return null; + + } + public override void Write(Utf8JsonWriter writer, Position position, JsonSerializerOptions options) + { + if (position == null) + { + return; + } + + writer.WriteStartObject(); + writer.WriteStartArray(PositionMetadataFields.Coordinates); + writer.WriteNumberValue(position.Longitude); + writer.WriteNumberValue(position.Latitude); + if (position.Altitude.HasValue) + { + writer.WriteNumberValue(position.Altitude.Value); + } + writer.WriteEndArray(); + writer.WriteNumber(PositionMetadataFields.Longitude, position.Longitude); + writer.WriteNumber(PositionMetadataFields.Latitude, position.Latitude); + if (position.Altitude.HasValue) + { + writer.WriteNumber(PositionMetadataFields.Altitude, position.Altitude.Value); + } + else + { + writer.WriteNull(PositionMetadataFields.Altitude); + + } + writer.WriteEndObject(); + + } + + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs index ace5eee506..0d77b0e4b7 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs @@ -34,7 +34,7 @@ public Point(double longitude, double latitude) /// /// Position of the point. /// - public Point(Position position) + internal Point(Position position) : this(position, new GeometryParams()) { } @@ -51,12 +51,7 @@ public Point(Position position) public Point(Position position, GeometryParams geometryParams) : base(GeometryType.Point, geometryParams) { - if (position == null) - { - throw new ArgumentNullException("position"); - } - - this.Position = position; + this.Position = position ?? throw new ArgumentNullException("position"); } /// @@ -76,9 +71,9 @@ public Point() /// /// Coordinates of the point. /// - [DataMember(Name = "coordinates")] - [JsonProperty("coordinates", Required = Required.Always, Order = 1)] - public Position Position { get; set; } + [DataMember(Name = PositionMetadataFields.Coordinates)] + [JsonProperty(PositionMetadataFields.Coordinates, Required = Required.Always, Order = 1)] + public Position Position { get; private set; } /// /// Determines if this is equal to in the Azure Cosmos DB service. @@ -87,7 +82,7 @@ public Point() /// true if objects are equal. false otherwise. public bool Equals(Point other) { - if (object.ReferenceEquals(null, other)) + if (other is null) { return false; } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs index 72e800b5f4..985a2da023 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs @@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Linq; using System.Runtime.Serialization; using Converters; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -23,6 +24,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(PositionJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(PositionSTJJsonConverter))] public sealed class Position : IEquatable { /// @@ -38,7 +40,8 @@ public Position(double longitude, double latitude) : this(longitude, latitude, null) { } - + + /* /// /// Initializes a new instance of the class in the Azure Cosmos DB service. /// @@ -46,6 +49,7 @@ public Position() : this(0.0d, 0.0d) { } + */ /// /// Initializes a new instance of the class in the Azure Cosmos DB service. @@ -61,14 +65,9 @@ public Position() /// public Position(double longitude, double latitude, double? altitude) { - if (altitude != null) - { - this.Coordinates = new List(new[] { longitude, latitude, altitude.Value }); - } - else - { - this.Coordinates = new List(new[] { longitude, latitude }); - } + this.Coordinates = altitude != null + ? new ReadOnlyCollection(new[] { longitude, latitude, altitude.Value }) + : new ReadOnlyCollection(new[] { longitude, latitude }); } /// @@ -84,7 +83,7 @@ public Position(IList coordinates) throw new ArgumentException("coordinates"); } - this.Coordinates = new List(coordinates); + this.Coordinates = new ReadOnlyCollection(coordinates); } /// @@ -94,7 +93,7 @@ public Position(IList coordinates) /// Coordinate values. /// [DataMember(Name = "Coordinates")] - public List Coordinates { get; set; } + public ReadOnlyCollection Coordinates { get; private set; } /// /// Gets longitude in the Azure Cosmos DB service. @@ -102,6 +101,7 @@ public Position(IList coordinates) /// /// Longitude value. /// + [JsonProperty(PropertyName = PositionMetadataFields.Longitude, NullValueHandling = NullValueHandling.Ignore)] public double Longitude => this.Coordinates[0]; /// @@ -110,6 +110,7 @@ public Position(IList coordinates) /// /// Latitude value. /// + [JsonProperty(PropertyName = PositionMetadataFields.Latitude, NullValueHandling = NullValueHandling.Ignore)] public double Latitude => this.Coordinates[1]; /// @@ -118,6 +119,7 @@ public Position(IList coordinates) /// /// Altitude value. /// + [JsonProperty(PropertyName = PositionMetadataFields.Altitude, NullValueHandling = NullValueHandling.Ignore)] public double? Altitude => this.Coordinates.Count > 2 ? (double?)this.Coordinates[2] : null; /// @@ -153,7 +155,7 @@ public override int GetHashCode() /// true if objects are equal. false otherwise. public bool Equals(Position other) { - if (object.ReferenceEquals(null, other)) + if (other is null) { return false; } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs b/Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs new file mode 100644 index 0000000000..5a3cd2e5f4 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs @@ -0,0 +1,19 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial +{ + using System; + using System.Collections.Generic; + using System.Text; + + internal class PositionMetadataFields + { + public const string Latitude = "latitude"; + public const string Longitude = "longitude"; + public const string Altitude = "altitude"; + public const string Coordinates = "coordinates"; + + } +} From cb18173db506d2511258d481dc56a40422e6d8ee Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Mon, 28 Oct 2024 11:03:18 -0500 Subject: [PATCH 3/9] WIP: STJ Serialization/DeSerialization --- .../src/Spatial/BoundingBox.cs | 2 + .../BoundingBoxSTJJsonConverter.cs | 70 ++++++++ .../STJConverters/CrsSTJJsonConverter.cs | 103 ++++++++++++ .../STJConverters/PointSTJJsonConverter.cs | 158 ++++++++++++++++++ .../STJConverters/PositionSTJJsonConverter.cs | 6 +- Microsoft.Azure.Cosmos/src/Spatial/Crs.cs | 2 + Microsoft.Azure.Cosmos/src/Spatial/Point.cs | 6 +- .../ClientTests.cs | 38 ++++- 8 files changed, 379 insertions(+), 6 deletions(-) create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJJsonConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJJsonConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJJsonConverter.cs diff --git a/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs b/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs index b80232a691..9084e5910b 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs @@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System; using System.Runtime.Serialization; using Microsoft.Azure.Cosmos.Spatial.Converters; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -14,6 +15,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(BoundingBoxJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(BoundingBoxSTJJsonConverter))] public sealed class BoundingBox : IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJJsonConverter.cs new file mode 100644 index 0000000000..9501dbf0c3 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJJsonConverter.cs @@ -0,0 +1,70 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Documents; + using static System.Text.Json.JsonElement; + + internal class BoundingBoxSTJJsonConverter : JsonConverter + { + public override BoundingBox Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + Position min = null; + Position max = null; + + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("min")) + { + min = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("max")) + { + max = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + } + + return new BoundingBox(min, max); + } + + public override void Write(Utf8JsonWriter writer, BoundingBox box, JsonSerializerOptions options) + { + if (box == null) + { + return; + } + + writer.WriteStartObject("boundingBox"); + + writer.WriteStartObject("min"); + System.Text.Json.JsonSerializer.Serialize(writer, box.Min, options); + writer.WriteEndObject(); + + writer.WriteStartObject("max"); + System.Text.Json.JsonSerializer.Serialize(writer, box.Max, options); + writer.WriteEndObject(); + + writer.WriteEndObject(); + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJJsonConverter.cs new file mode 100644 index 0000000000..dae7d84d3b --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJJsonConverter.cs @@ -0,0 +1,103 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Linq; + using Microsoft.Azure.Documents; + using static System.Text.Json.JsonElement; + + internal class CrsSTJJsonConverter : JsonConverter + { + public override Crs Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + if (reader.TokenType == JsonTokenType.Null) + { + return Crs.Unspecified; + } + + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + JsonElement properties = rootElement.GetProperty("properties"); + if (properties.ValueKind == JsonValueKind.Null || properties.ValueKind != JsonValueKind.Object) + { + throw new JsonException(RMResources.SpatialFailedToDeserializeCrs); + } + + JsonElement crsType = rootElement.GetProperty("type"); + if (crsType.ValueKind == JsonValueKind.Null || crsType.ValueKind != JsonValueKind.String) + { + throw new JsonException(RMResources.SpatialFailedToDeserializeCrs); + } + + switch (crsType.GetString()) + { + case "name": + string crsName = properties.GetProperty("name").GetString(); + return new NamedCrs(crsName); + + case "link": + string crsHref = properties.GetProperty("href").GetString(); + string crsHrefType = properties.GetProperty("type").GetString(); + return new LinkedCrs(crsHref, crsHrefType); + + default: + throw new JsonException(RMResources.SpatialFailedToDeserializeCrs); + } + + } + public override void Write(Utf8JsonWriter writer, Crs crs, JsonSerializerOptions options) + { + if (crs == null) + { + return; + } + + switch (crs.Type) + { + case CrsType.Linked: + writer.WriteStartObject("crs"); + LinkedCrs linkedCrs = (LinkedCrs)crs; + writer.WriteString("type", "link"); + writer.WritePropertyName("properties"); + writer.WriteStartObject(); + writer.WriteString("href", linkedCrs.Href); + if (linkedCrs.HrefType != null) + { + writer.WriteString("type", linkedCrs.HrefType); + } + + writer.WriteEndObject(); + writer.WriteEndObject(); + break; + + case CrsType.Named: + writer.WriteStartObject("crs"); + NamedCrs namedCrs = (NamedCrs)crs; + writer.WriteString("type", "name"); + writer.WritePropertyName("properties"); + writer.WriteStartObject(); + writer.WriteString("name", namedCrs.Name); + writer.WriteEndObject(); + + writer.WriteEndObject(); + break; + + case CrsType.Unspecified: + writer.WriteNull("crs"); + break; + } + + } + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJJsonConverter.cs new file mode 100644 index 0000000000..d3e6d1df2b --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJJsonConverter.cs @@ -0,0 +1,158 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + internal class PointSTJJsonConverter : JsonConverter + { + public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + Position pos = null; + Dictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("position")) + { + pos = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + //Console.WriteLine(pos.ToString()); + } + else if (property.NameEquals("additionalProperties")) + { + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + //Console.WriteLine(additionalProperties.ToString()); + //Point point = new Point(pos, new GeometryParams() { AdditionalProperties = additionalProperties }); + //return point; + + } + else if (property.NameEquals("crs")) + { + crs = property.Value.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("boundingBox")) + { + boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + + } + return new Point(pos, new GeometryParams + { + AdditionalProperties = additionalProperties, + BoundingBox = boundingBox, + Crs = crs + }); + + /*Point point = new Point( + new Position(20, 30), + new GeometryParams + { + AdditionalProperties = new Dictionary + { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + }, + //BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + //Crs = new UnspecifiedCrs() + }); + /*JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals(PositionMetadataFields.Coordinates)) + { + IList coordinates = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + coordinates.Add(arrayElement.GetDouble()); + } + + return new Position(new ReadOnlyCollection(coordinates)); + + } + + }*/ + } + public override void Write(Utf8JsonWriter writer, Point point, JsonSerializerOptions options) + { + if (point == null) + { + return; + } + + writer.WriteStartObject(); + + writer.WriteStartObject("position"); + System.Text.Json.JsonSerializer.Serialize(writer, point.Position, options); + writer.WriteEndObject(); + + System.Text.Json.JsonSerializer.Serialize(writer, point.Crs, options); + + writer.WriteNumber("type", (int)point.Type); + + //writer.WriteStartObject("bbox"); + System.Text.Json.JsonSerializer.Serialize(writer, point.BoundingBox, options); + //writer.WriteEndObject(); + + if (point.AdditionalProperties.Count > 0) + { + writer.WriteStartObject("additionalProperties"); + foreach (KeyValuePair keyValue in point.AdditionalProperties) + { + writer.WritePropertyName(keyValue.Key); + System.Text.Json.JsonSerializer.Serialize(writer, keyValue.Value, options); + } + writer.WriteEndObject(); + } + + //System.Text.Json.JsonSerializer.Serialize(writer, point.Crs, options); + //System.Text.Json.JsonSerializer.Serialize(writer, point., options); + + /*writer.WriteStartArray(PositionMetadataFields.Coordinates); + writer.WriteNumberValue(position.Longitude); + writer.WriteNumberValue(position.Latitude); + if (position.Altitude.HasValue) + { + writer.WriteNumberValue(position.Altitude.Value); + } + writer.WriteEndArray(); + writer.WriteNumber(PositionMetadataFields.Longitude, position.Longitude); + writer.WriteNumber(PositionMetadataFields.Latitude, position.Latitude); + if (position.Altitude.HasValue) + { + writer.WriteNumber(PositionMetadataFields.Altitude, position.Altitude.Value); + } + else + { + writer.WriteNull(PositionMetadataFields.Altitude); + + }*/ + writer.WriteEndObject(); + //writer.WriteEndObject(); + + } + + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs index ee91780cab..8c3f4d87a1 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs @@ -30,7 +30,6 @@ public override Position Read(ref Utf8JsonReader reader, Type typeToConvert, Jso } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; - //Position position = new Position(); foreach (JsonProperty property in rootElement.EnumerateObject()) { if (property.NameEquals(PositionMetadataFields.Coordinates)) @@ -56,7 +55,8 @@ public override void Write(Utf8JsonWriter writer, Position position, JsonSeriali return; } - writer.WriteStartObject(); + //writer.WriteStartObject("position"); + writer.WriteStartArray(PositionMetadataFields.Coordinates); writer.WriteNumberValue(position.Longitude); writer.WriteNumberValue(position.Latitude); @@ -76,7 +76,7 @@ public override void Write(Utf8JsonWriter writer, Position position, JsonSeriali writer.WriteNull(PositionMetadataFields.Altitude); } - writer.WriteEndObject(); + //writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs b/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs index 94427b701b..dbbc5f7076 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs @@ -6,6 +6,7 @@ namespace Microsoft.Azure.Cosmos.Spatial { using System.Runtime.Serialization; using Microsoft.Azure.Cosmos.Spatial.Converters; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -13,6 +14,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(CrsJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(CrsSTJJsonConverter))] public abstract class Crs { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs index 0d77b0e4b7..a7f8d2a82f 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs @@ -6,12 +6,14 @@ namespace Microsoft.Azure.Cosmos.Spatial { using System; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// /// Point geometry class in the Azure Cosmos DB service. /// [DataContract] + [System.Text.Json.Serialization.JsonConverter(typeof(PointSTJJsonConverter))] public sealed class Point : Geometry, IEquatable { /// @@ -34,7 +36,7 @@ public Point(double longitude, double latitude) /// /// Position of the point. /// - internal Point(Position position) + public Point(Position position) : this(position, new GeometryParams()) { } @@ -60,7 +62,7 @@ public Point(Position position, GeometryParams geometryParams) /// /// This constructor is used only during deserialization. /// - public Point() + internal Point() : base(GeometryType.Point, new GeometryParams()) { } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 0aeef26d51..b749285809 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -31,6 +31,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using Newtonsoft.Json.Linq; using Microsoft.Azure.Cosmos.Spatial; using System.Text.Json; + //using System.Drawing; [TestClass] public class ClientTests @@ -959,11 +960,46 @@ public async Task ValidateSpatialPointJSONSerialization() Cosmos.Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync("AzureCosmosSpatialSerialization"); Container container = await database.CreateContainerIfNotExistsAsync("spatial-items", "/id"); + + /*Point point = new Point( + new Position(20, 30), + new GeometryParams + { + /*AdditionalProperties = new Dictionary { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + },*/ + //BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + //Crs = Crs.Named("SomeCrs") + //Crs = new UnspecifiedCrs() + //});*/ + Point point = new Point( + new Position(20.3, 30.5), + new GeometryParams + { + BoundingBox = new BoundingBox(new Position(1.0, 2.0), new Position(40.0, 40.2)), + Crs = new UnspecifiedCrs() + + }); + + + /*Point point = new Point( + new Position(20, 30) + );*/ + + + /*Dictionary dictionary = new Dictionary + { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + };*/ + + SpatialItem inputItem = new SpatialItem() { Id = GUID, Name = "Spatial Point", - Location = new Point(1, 1) + Location = point }; SpatialItem result = await container.CreateItemAsync(inputItem); From ecf7d07702ebccb24b54b22b59418b05442e8a51 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Thu, 31 Oct 2024 13:34:38 -0500 Subject: [PATCH 4/9] WIP: STJ Serialization/DeSerialization --- .../CosmosSystemTextJsonSerializer.cs | 4 +- .../src/Spatial/BoundingBox.cs | 2 +- ...onverter.cs => BoundingBoxSTJConverter.cs} | 2 +- ...STJJsonConverter.cs => CrsSTJConverter.cs} | 2 +- .../STJConverters/DictionarySTJConverter.cs | 69 +++++++++ .../GeometryCollectionSTJConverter.cs | 134 ++++++++++++++++++ .../STJConverters/GeometryParamsHelper.cs | 15 ++ .../LineStringCoordinatesSTJConverter.cs | 68 +++++++++ .../STJConverters/LineStringSTJConverter.cs | 107 ++++++++++++++ .../STJConverters/LinearRingSTJConverter.cs | 68 +++++++++ .../MultiLineStringSTJConverter.cs | 108 ++++++++++++++ .../STJConverters/MultiPointSTJConverter.cs | 107 ++++++++++++++ .../STJConverters/MultiPolygonSTJConverter.cs | 109 ++++++++++++++ ...JJsonConverter.cs => PointSTJConverter.cs} | 84 +++-------- .../PolygonCoordinatesSTJConverter.cs | 68 +++++++++ .../STJConverters/PolygonSTJConverter.cs | 108 ++++++++++++++ ...onConverter.cs => PositionSTJConverter.cs} | 2 +- Microsoft.Azure.Cosmos/src/Spatial/Crs.cs | 2 +- .../src/Spatial/GeometryCollection.cs | 2 + .../src/Spatial/LineString.cs | 2 + .../src/Spatial/LineStringCoordinates.cs | 2 + .../src/Spatial/LinearRing.cs | 2 + .../src/Spatial/MultiLineString.cs | 2 + .../src/Spatial/MultiPoint.cs | 2 + .../src/Spatial/MultiPolygon.cs | 2 + Microsoft.Azure.Cosmos/src/Spatial/Point.cs | 2 +- Microsoft.Azure.Cosmos/src/Spatial/Polygon.cs | 2 + .../src/Spatial/PolygonCoordinates.cs | 2 + .../src/Spatial/Position.cs | 2 +- .../ClientTests.cs | 62 +++++++- .../Spatial/STJSpatialTest.cs | 64 +++++++++ 31 files changed, 1127 insertions(+), 80 deletions(-) rename Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/{BoundingBoxSTJJsonConverter.cs => BoundingBoxSTJConverter.cs} (96%) rename Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/{CrsSTJJsonConverter.cs => CrsSTJConverter.cs} (98%) create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs rename Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/{PointSTJJsonConverter.cs => PointSTJConverter.cs} (50%) create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs rename Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/{PositionSTJJsonConverter.cs => PositionSTJConverter.cs} (97%) create mode 100644 Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs index ac5550b128..f4fdaa30f0 100644 --- a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs +++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; /// /// This class provides a default implementation of System.Text.Json Cosmos Linq Serializer. @@ -29,6 +30,8 @@ internal CosmosSystemTextJsonSerializer( JsonSerializerOptions jsonSerializerOptions) { this.jsonSerializerOptions = jsonSerializerOptions; + //somehow adding a .NET native type converter as an attribute on properties doesnt take effect. In this case I tried adding it to AdditionalProperties of Geometry class. + this.jsonSerializerOptions.Converters.Add(new DictionarySTJConverter()); } /// @@ -59,7 +62,6 @@ public override Stream ToStream(T input) { MemoryStream streamPayload = new (); using Utf8JsonWriter writer = new (streamPayload); - JsonSerializer.Serialize(writer, input, this.jsonSerializerOptions); streamPayload.Position = 0; diff --git a/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs b/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs index 9084e5910b..2219811f4c 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/BoundingBox.cs @@ -15,7 +15,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(BoundingBoxJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(BoundingBoxSTJJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(BoundingBoxSTJConverter))] public sealed class BoundingBox : IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs similarity index 96% rename from Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJJsonConverter.cs rename to Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs index 9501dbf0c3..7bd120daed 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJJsonConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs @@ -14,7 +14,7 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters using Microsoft.Azure.Documents; using static System.Text.Json.JsonElement; - internal class BoundingBoxSTJJsonConverter : JsonConverter + internal class BoundingBoxSTJConverter : JsonConverter { public override BoundingBox Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs similarity index 98% rename from Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJJsonConverter.cs rename to Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs index dae7d84d3b..5a120c1982 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJJsonConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs @@ -14,7 +14,7 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters using Microsoft.Azure.Documents; using static System.Text.Json.JsonElement; - internal class CrsSTJJsonConverter : JsonConverter + internal class CrsSTJConverter : JsonConverter { public override Crs Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs new file mode 100644 index 0000000000..67a5a4e314 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs @@ -0,0 +1,69 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + // System.Text.Json by default returns JsonElement as value for a key in dictionary object as it cant infer the type of the value data. This Converter is required to property return .NET type instead of JsonElement back to the client. + internal class DictionarySTJConverter : JsonConverter> + { + public override IDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + Dictionary dictionary = new Dictionary(); + + while (reader.Read()) + { + if (reader.TokenType == JsonTokenType.EndObject) + { + return dictionary; + } + if (reader.TokenType != JsonTokenType.PropertyName) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + string propertyName = reader.GetString(); + reader.Read(); // get the value + object value = this.getValue(ref reader, options); + dictionary.Add(propertyName, value); + } + + return dictionary; + + } + public override void Write(Utf8JsonWriter writer, IDictionary dict, JsonSerializerOptions options) + { + System.Text.Json.JsonSerializer.Serialize(writer, (Dictionary)dict, options); + + } + + private object getValue(ref Utf8JsonReader reader, JsonSerializerOptions options) + { + return reader.TokenType switch + { + JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => datetime, + JsonTokenType.String => reader.GetString(), + JsonTokenType.True => true, + JsonTokenType.False => false, + JsonTokenType.Number when reader.TryGetInt64(out long l) => l, + JsonTokenType.Number => reader.GetDouble(), + JsonTokenType.Null => null, + JsonTokenType.StartObject => this.Read(ref reader, null!, options), + _ => throw new JsonException(RMResources.JsonUnexpectedToken) + }; + } + + } +} \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs new file mode 100644 index 0000000000..97c738aa1b --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs @@ -0,0 +1,134 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + using Point = Point; + + internal class GeometryCollectionSTJConverter : JsonConverter + { + public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + IList geometries = null; + IDictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("geometries")) + { + geometries = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + Geometry geometry = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(geometry); + } + } + else if (property.NameEquals("additionalProperties")) + { + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + Console.WriteLine(additionalProperties.ToString()); + } + else if (property.NameEquals("crs")) + { + crs = property.Value.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("boundingBox")) + { + boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + + } + return new GeometryCollection(geometries, new GeometryParams + { + AdditionalProperties = additionalProperties, + BoundingBox = boundingBox, + Crs = crs + }); + + } + public override void Write(Utf8JsonWriter writer, GeometryCollection geometryCollection, JsonSerializerOptions options) + { + if (geometryCollection == null) + { + return; + } + writer.WriteStartObject(); + writer.WriteStartArray("geometries"); + foreach (Geometry geometry in geometryCollection.Geometries) + { + if (geometry.GetType() == typeof(Point)) + { + System.Text.Json.JsonSerializer.Serialize(writer, (Point)geometry, options); + } + else if (geometry.GetType() == typeof(MultiPoint)) + { + System.Text.Json.JsonSerializer.Serialize(writer, (MultiPoint)geometry, options); + } + else if (geometry.GetType() == typeof(LineString)) + { + System.Text.Json.JsonSerializer.Serialize(writer, (LineString)geometry, options); + } + else if (geometry.GetType() == typeof(MultiLineString)) + { + System.Text.Json.JsonSerializer.Serialize(writer, (MultiLineString)geometry, options); + } + else if (geometry.GetType() == typeof(Polygon)) + { + System.Text.Json.JsonSerializer.Serialize(writer, (Polygon)geometry, options); + } + else if (geometry.GetType() == typeof(MultiPolygon)) + { + System.Text.Json.JsonSerializer.Serialize(writer, (MultiPolygon)geometry, options); + } + else if (geometry.GetType() == typeof(GeometryCollection)) + { + System.Text.Json.JsonSerializer.Serialize(writer, (GeometryCollection)geometry, options); + } + + } + + writer.WriteEndArray(); + System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.Crs, options); + writer.WriteNumber("type", (int)geometryCollection.Type); + if (geometryCollection.BoundingBox != null) + { + System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.BoundingBox, options); + } + if (geometryCollection.AdditionalProperties.Count > 0) + { + writer.WritePropertyName("additionalProperties"); + System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.AdditionalProperties, options); + + } + + writer.WriteEndObject(); + + } + + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs new file mode 100644 index 0000000000..a60a20f142 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs @@ -0,0 +1,15 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections.Generic; + using System.Text; + + internal class GeometryParamsHelper + { + //This a new file + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs new file mode 100644 index 0000000000..da8fa7a292 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs @@ -0,0 +1,68 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + + internal class LineStringCoordinatesSTJConverter : JsonConverter + { + public override LineStringCoordinates Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + IList positions = null; + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("positions")) + { + positions = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + positions.Add(pos); + } + } + + } + return new LineStringCoordinates(positions); + + } + public override void Write(Utf8JsonWriter writer, LineStringCoordinates lineStringCorodinates, JsonSerializerOptions options) + { + if (lineStringCorodinates == null) + { + return; + } + writer.WriteStartArray("positions"); + foreach (Position position in lineStringCorodinates.Positions) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, position, options); + writer.WriteEndObject(); + } + + writer.WriteEndArray(); + + } + + } + +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs new file mode 100644 index 0000000000..a28dc67e12 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs @@ -0,0 +1,107 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + + internal class LineStringSTJConverter : JsonConverter + { + public override LineString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + IList positions = null; + IDictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("positions")) + { + positions = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + positions.Add(pos); + } + } + else if (property.NameEquals("additionalProperties")) + { + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + } + else if (property.NameEquals("crs")) + { + crs = property.Value.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("boundingBox")) + { + boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + + } + return new LineString(positions, new GeometryParams + { + AdditionalProperties = additionalProperties, + BoundingBox = boundingBox, + Crs = crs + }); + } + public override void Write(Utf8JsonWriter writer, LineString lineString, JsonSerializerOptions options) + { + if (lineString == null) + { + return; + } + + writer.WriteStartObject(); + + writer.WriteStartArray("positions"); + foreach (Position position in lineString.Positions) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, position, options); + writer.WriteEndObject(); + } + writer.WriteEndArray(); + + System.Text.Json.JsonSerializer.Serialize(writer, lineString.Crs, options); + writer.WriteNumber("type", (int)lineString.Type); + if (lineString.BoundingBox != null) + { + System.Text.Json.JsonSerializer.Serialize(writer, lineString.BoundingBox, options); + } + if (lineString.AdditionalProperties.Count > 0) + { + writer.WritePropertyName("additionalProperties"); + System.Text.Json.JsonSerializer.Serialize(writer, lineString.AdditionalProperties, options); + + } + + writer.WriteEndObject(); + } + + } + +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs new file mode 100644 index 0000000000..1a37c5b243 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs @@ -0,0 +1,68 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + + internal class LinearRingSTJConverter : JsonConverter + { + public override LinearRing Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + IList positions = null; + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("positions")) + { + positions = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + positions.Add(pos); + } + } + + } + return new LinearRing(positions); + + } + public override void Write(Utf8JsonWriter writer, LinearRing linearRing, JsonSerializerOptions options) + { + if (linearRing == null) + { + return; + } + writer.WriteStartArray("positions"); + foreach (Position position in linearRing.Positions) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, position, options); + writer.WriteEndObject(); + } + + writer.WriteEndArray(); + + } + + } + +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs new file mode 100644 index 0000000000..2b85d94ffb --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs @@ -0,0 +1,108 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + internal class MultiLineStringSTJConverter : JsonConverter + { + public override MultiLineString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + IList coordinates = null; + IDictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("lineStrings")) + { + coordinates = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + LineStringCoordinates lineStringCoordinate = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + coordinates.Add(lineStringCoordinate); + } + } + else if (property.NameEquals("additionalProperties")) + { + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + Console.WriteLine(additionalProperties.ToString()); + } + else if (property.NameEquals("crs")) + { + crs = property.Value.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("boundingBox")) + { + boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + + } + return new MultiLineString(coordinates, new GeometryParams + { + AdditionalProperties = additionalProperties, + BoundingBox = boundingBox, + Crs = crs + }); + + } + public override void Write(Utf8JsonWriter writer, MultiLineString multiLineString, JsonSerializerOptions options) + { + if (multiLineString == null) + { + return; + } + + writer.WriteStartObject(); + + writer.WriteStartArray("lineStrings"); + foreach (LineStringCoordinates coordinates in multiLineString.LineStrings) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, coordinates, options); + writer.WriteEndObject(); + } + writer.WriteEndArray(); + + System.Text.Json.JsonSerializer.Serialize(writer, multiLineString.Crs, options); + writer.WriteNumber("type", (int)multiLineString.Type); + if (multiLineString.BoundingBox != null) + { + System.Text.Json.JsonSerializer.Serialize(writer, multiLineString.BoundingBox, options); + } + if (multiLineString.AdditionalProperties.Count > 0) + { + writer.WritePropertyName("additionalProperties"); + System.Text.Json.JsonSerializer.Serialize(writer, multiLineString.AdditionalProperties, options); + + } + + writer.WriteEndObject(); + } + + } + +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs new file mode 100644 index 0000000000..e16b094e53 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs @@ -0,0 +1,107 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + + internal class MultiPointSTJConverter : JsonConverter + { + public override MultiPoint Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + IList positions = null; + IDictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("points")) + { + positions = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + positions.Add(pos); + } + } + else if (property.NameEquals("additionalProperties")) + { + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + Console.WriteLine(additionalProperties.ToString()); + } + else if (property.NameEquals("crs")) + { + crs = property.Value.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("boundingBox")) + { + boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + + } + return new MultiPoint(positions, new GeometryParams + { + AdditionalProperties = additionalProperties, + BoundingBox = boundingBox, + Crs = crs + }); + } + public override void Write(Utf8JsonWriter writer, MultiPoint multiPoint, JsonSerializerOptions options) + { + if (multiPoint == null) + { + return; + } + + writer.WriteStartObject(); + + writer.WriteStartArray("points"); + foreach (Position position in multiPoint.Points) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, position, options); + writer.WriteEndObject(); + } + writer.WriteEndArray(); + + System.Text.Json.JsonSerializer.Serialize(writer, multiPoint.Crs, options); + writer.WriteNumber("type", (int)multiPoint.Type); + if (multiPoint.BoundingBox != null) + { + System.Text.Json.JsonSerializer.Serialize(writer, multiPoint.BoundingBox, options); + } + if (multiPoint.AdditionalProperties.Count > 0) + { + writer.WritePropertyName("additionalProperties"); + System.Text.Json.JsonSerializer.Serialize(writer, multiPoint.AdditionalProperties, options); + + } + + writer.WriteEndObject(); + } + + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs new file mode 100644 index 0000000000..650be7cc78 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs @@ -0,0 +1,109 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + + internal class MultiPolygonSTJConverter : JsonConverter + { + public override MultiPolygon Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + IList coordinates = null; + IDictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("polygons")) + { + coordinates = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + PolygonCoordinates coordinate = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + coordinates.Add(coordinate); + } + } + else if (property.NameEquals("additionalProperties")) + { + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + Console.WriteLine(additionalProperties.ToString()); + } + else if (property.NameEquals("crs")) + { + crs = property.Value.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("boundingBox")) + { + boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + + } + return new MultiPolygon(coordinates, new GeometryParams + { + AdditionalProperties = additionalProperties, + BoundingBox = boundingBox, + Crs = crs + }); + + } + public override void Write(Utf8JsonWriter writer, MultiPolygon multiPolygon, JsonSerializerOptions options) + { + if (multiPolygon == null) + { + return; + } + + writer.WriteStartObject(); + + writer.WriteStartArray("polygons"); + foreach (PolygonCoordinates coordinates in multiPolygon.Polygons) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, coordinates, options); + writer.WriteEndObject(); + } + writer.WriteEndArray(); + + System.Text.Json.JsonSerializer.Serialize(writer, multiPolygon.Crs, options); + writer.WriteNumber("type", (int)multiPolygon.Type); + if (multiPolygon.BoundingBox != null) + { + System.Text.Json.JsonSerializer.Serialize(writer, multiPolygon.BoundingBox, options); + } + if (multiPolygon.AdditionalProperties.Count > 0) + { + writer.WritePropertyName("additionalProperties"); + System.Text.Json.JsonSerializer.Serialize(writer, multiPolygon.AdditionalProperties, options); + + } + + writer.WriteEndObject(); + } + + } + +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs similarity index 50% rename from Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJJsonConverter.cs rename to Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs index d3e6d1df2b..1fee7f4d34 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJJsonConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs @@ -10,9 +10,11 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; + using Antlr4.Runtime.Sharpen; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - internal class PointSTJJsonConverter : JsonConverter + + internal class PointSTJConverter : JsonConverter { public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { @@ -26,7 +28,7 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; Position pos = null; - Dictionary additionalProperties = null; + IDictionary additionalProperties = null; Crs crs = null; BoundingBox boundingBox = null; foreach (JsonProperty property in rootElement.EnumerateObject()) @@ -34,14 +36,10 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe if (property.NameEquals("position")) { pos = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); - //Console.WriteLine(pos.ToString()); } else if (property.NameEquals("additionalProperties")) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); - //Console.WriteLine(additionalProperties.ToString()); - //Point point = new Point(pos, new GeometryParams() { AdditionalProperties = additionalProperties }); - //return point; + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); } else if (property.NameEquals("crs")) @@ -65,35 +63,6 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe Crs = crs }); - /*Point point = new Point( - new Position(20, 30), - new GeometryParams - { - AdditionalProperties = new Dictionary - { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" - }, - //BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), - Crs = Crs.Named("SomeCrs") - //Crs = new UnspecifiedCrs() - }); - /*JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; - foreach (JsonProperty property in rootElement.EnumerateObject()) - { - if (property.NameEquals(PositionMetadataFields.Coordinates)) - { - IList coordinates = new List(); - foreach (JsonElement arrayElement in property.Value.EnumerateArray()) - { - coordinates.Add(arrayElement.GetDouble()); - } - - return new Position(new ReadOnlyCollection(coordinates)); - - } - - }*/ } public override void Write(Utf8JsonWriter writer, Point point, JsonSerializerOptions options) { @@ -111,48 +80,27 @@ public override void Write(Utf8JsonWriter writer, Point point, JsonSerializerOpt System.Text.Json.JsonSerializer.Serialize(writer, point.Crs, options); writer.WriteNumber("type", (int)point.Type); - - //writer.WriteStartObject("bbox"); - System.Text.Json.JsonSerializer.Serialize(writer, point.BoundingBox, options); - //writer.WriteEndObject(); + + if (point.BoundingBox != null) + { + System.Text.Json.JsonSerializer.Serialize(writer, point.BoundingBox, options); + } if (point.AdditionalProperties.Count > 0) { - writer.WriteStartObject("additionalProperties"); - foreach (KeyValuePair keyValue in point.AdditionalProperties) + //writer.WriteStartObject("additionalProperties"); + writer.WritePropertyName("additionalProperties"); + /*foreach (KeyValuePair keyValue in point.AdditionalProperties) { writer.WritePropertyName(keyValue.Key); System.Text.Json.JsonSerializer.Serialize(writer, keyValue.Value, options); - } - writer.WriteEndObject(); + }*/ + System.Text.Json.JsonSerializer.Serialize(writer, point.AdditionalProperties, options); + //writer.WriteEndObject(); } - //System.Text.Json.JsonSerializer.Serialize(writer, point.Crs, options); - //System.Text.Json.JsonSerializer.Serialize(writer, point., options); - - /*writer.WriteStartArray(PositionMetadataFields.Coordinates); - writer.WriteNumberValue(position.Longitude); - writer.WriteNumberValue(position.Latitude); - if (position.Altitude.HasValue) - { - writer.WriteNumberValue(position.Altitude.Value); - } - writer.WriteEndArray(); - writer.WriteNumber(PositionMetadataFields.Longitude, position.Longitude); - writer.WriteNumber(PositionMetadataFields.Latitude, position.Latitude); - if (position.Altitude.HasValue) - { - writer.WriteNumber(PositionMetadataFields.Altitude, position.Altitude.Value); - } - else - { - writer.WriteNull(PositionMetadataFields.Altitude); - - }*/ writer.WriteEndObject(); - //writer.WriteEndObject(); } - } } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs new file mode 100644 index 0000000000..9b14d4a464 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs @@ -0,0 +1,68 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + + internal class PolygonCoordinatesSTJConverter : JsonConverter + { + public override PolygonCoordinates Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + IList linearRings = null; + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("rings")) + { + linearRings = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + LinearRing ring = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + linearRings.Add(ring); + } + } + + } + return new PolygonCoordinates(linearRings); + + } + public override void Write(Utf8JsonWriter writer, PolygonCoordinates polygonCoordinates, JsonSerializerOptions options) + { + if (polygonCoordinates == null) + { + return; + } + writer.WriteStartArray("rings"); + foreach (LinearRing ring in polygonCoordinates.Rings) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, ring, options); + writer.WriteEndObject(); + } + + writer.WriteEndArray(); + + } + + } + +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs new file mode 100644 index 0000000000..83e956f6b9 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs @@ -0,0 +1,108 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Globalization; + using System.Text.Json; + using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Documents; + + internal class PolygonSTJConverter : JsonConverter + { + public override Polygon Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return null; + } + if (reader.TokenType != JsonTokenType.StartObject) + { + throw new JsonException(RMResources.JsonUnexpectedToken); + } + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; + IList linearRings = null; + IDictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + foreach (JsonProperty property in rootElement.EnumerateObject()) + { + if (property.NameEquals("rings")) + { + linearRings = new List(); + foreach (JsonElement arrayElement in property.Value.EnumerateArray()) + { + LinearRing linearRing = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + linearRings.Add(linearRing); + } + } + else if (property.NameEquals("additionalProperties")) + { + additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + Console.WriteLine(additionalProperties.ToString()); + } + else if (property.NameEquals("crs")) + { + crs = property.Value.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + else if (property.NameEquals("boundingBox")) + { + boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + + } + + } + return new Polygon(linearRings, new GeometryParams + { + AdditionalProperties = additionalProperties, + BoundingBox = boundingBox, + Crs = crs + }); + + } + public override void Write(Utf8JsonWriter writer, Polygon polygon, JsonSerializerOptions options) + { + if (polygon == null) + { + return; + } + + writer.WriteStartObject(); + + writer.WriteStartArray("rings"); + foreach (LinearRing linearRing in polygon.Rings) + { + writer.WriteStartObject(); + System.Text.Json.JsonSerializer.Serialize(writer, linearRing, options); + writer.WriteEndObject(); + } + writer.WriteEndArray(); + + System.Text.Json.JsonSerializer.Serialize(writer, polygon.Crs, options); + writer.WriteNumber("type", (int)polygon.Type); + if (polygon.BoundingBox != null) + { + System.Text.Json.JsonSerializer.Serialize(writer, polygon.BoundingBox, options); + } + if (polygon.AdditionalProperties.Count > 0) + { + writer.WritePropertyName("additionalProperties"); + System.Text.Json.JsonSerializer.Serialize(writer, polygon.AdditionalProperties, options); + + } + + writer.WriteEndObject(); + } + + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJConverter.cs similarity index 97% rename from Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs rename to Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJConverter.cs index 8c3f4d87a1..bcdc652ec9 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJJsonConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJConverter.cs @@ -16,7 +16,7 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters /// /// Converter used to support System.Text.Json de/serialization of type Position/>. /// - internal class PositionSTJJsonConverter : JsonConverter + internal class PositionSTJConverter : JsonConverter { public override Position Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs b/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs index dbbc5f7076..5b31fbf628 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Crs.cs @@ -14,7 +14,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(CrsJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(CrsSTJJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(CrsSTJConverter))] public abstract class Crs { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/GeometryCollection.cs b/Microsoft.Azure.Cosmos/src/Spatial/GeometryCollection.cs index f14a753f05..d72b4e5588 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/GeometryCollection.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/GeometryCollection.cs @@ -9,12 +9,14 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// /// Represents a geometry consisting of other geometries. /// [DataContract] + [System.Text.Json.Serialization.JsonConverter(typeof(GeometryCollectionSTJConverter))] internal sealed class GeometryCollection : Geometry, IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/LineString.cs b/Microsoft.Azure.Cosmos/src/Spatial/LineString.cs index 00b2c077ac..ac291bc48f 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/LineString.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/LineString.cs @@ -9,12 +9,14 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// /// Represents a geometry consisting of connected line segments. /// [DataContract] + [System.Text.Json.Serialization.JsonConverter(typeof(LineStringSTJConverter))] public sealed class LineString : Geometry, IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/LineStringCoordinates.cs b/Microsoft.Azure.Cosmos/src/Spatial/LineStringCoordinates.cs index e231d78f5f..0e9258500f 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/LineStringCoordinates.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/LineStringCoordinates.cs @@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Linq; using System.Runtime.Serialization; using Converters; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -18,6 +19,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(LineStringCoordinatesJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(LineStringCoordinatesSTJConverter))] internal sealed class LineStringCoordinates : IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/LinearRing.cs b/Microsoft.Azure.Cosmos/src/Spatial/LinearRing.cs index 9437d9e623..5fc60a1112 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/LinearRing.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/LinearRing.cs @@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Linq; using System.Runtime.Serialization; using Microsoft.Azure.Cosmos.Spatial.Converters; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -20,6 +21,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(LinearRingJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(LinearRingSTJConverter))] public sealed class LinearRing : IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/MultiLineString.cs b/Microsoft.Azure.Cosmos/src/Spatial/MultiLineString.cs index 0ad888187b..602b18edb1 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/MultiLineString.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/MultiLineString.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -16,6 +17,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// /// . [DataContract] + [System.Text.Json.Serialization.JsonConverter(typeof(MultiLineStringSTJConverter))] internal sealed class MultiLineString : Geometry, IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/MultiPoint.cs b/Microsoft.Azure.Cosmos/src/Spatial/MultiPoint.cs index c4ed9e68c9..656d95f969 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/MultiPoint.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/MultiPoint.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -16,6 +17,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// /// . [DataContract] + [System.Text.Json.Serialization.JsonConverter(typeof(MultiPointSTJConverter))] internal sealed class MultiPoint : Geometry, IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/MultiPolygon.cs b/Microsoft.Azure.Cosmos/src/Spatial/MultiPolygon.cs index 83646dd1cd..cbd05b865f 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/MultiPolygon.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/MultiPolygon.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -16,6 +17,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// /// [DataContract] + [System.Text.Json.Serialization.JsonConverter(typeof(MultiPolygonSTJConverter))] public sealed class MultiPolygon : Geometry, IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs index a7f8d2a82f..79b19455c8 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs @@ -13,7 +13,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// Point geometry class in the Azure Cosmos DB service. /// [DataContract] - [System.Text.Json.Serialization.JsonConverter(typeof(PointSTJJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(PointSTJConverter))] public sealed class Point : Geometry, IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Polygon.cs b/Microsoft.Azure.Cosmos/src/Spatial/Polygon.cs index be22052cfa..75bc592fec 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Polygon.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Polygon.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Collections.ObjectModel; using System.Linq; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -58,6 +59,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// /// [DataContract] + [System.Text.Json.Serialization.JsonConverter(typeof(PolygonSTJConverter))] public sealed class Polygon : Geometry, IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/PolygonCoordinates.cs b/Microsoft.Azure.Cosmos/src/Spatial/PolygonCoordinates.cs index 5c7f3b65eb..3eced645bf 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/PolygonCoordinates.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/PolygonCoordinates.cs @@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Linq; using System.Runtime.Serialization; using Converters; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Newtonsoft.Json; /// @@ -18,6 +19,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(PolygonCoordinatesJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(PolygonCoordinatesSTJConverter))] public sealed class PolygonCoordinates : IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs index 985a2da023..8cc1253f7e 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs @@ -24,7 +24,7 @@ namespace Microsoft.Azure.Cosmos.Spatial /// [DataContract] [JsonConverter(typeof(PositionJsonConverter))] - [System.Text.Json.Serialization.JsonConverter(typeof(PositionSTJJsonConverter))] + [System.Text.Json.Serialization.JsonConverter(typeof(PositionSTJConverter))] public sealed class Position : IEquatable { /// diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index b749285809..230392381c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -973,14 +973,14 @@ public async Task ValidateSpatialPointJSONSerialization() //Crs = Crs.Named("SomeCrs") //Crs = new UnspecifiedCrs() //});*/ - Point point = new Point( + /*Point point = new Point( new Position(20.3, 30.5), new GeometryParams { BoundingBox = new BoundingBox(new Position(1.0, 2.0), new Position(40.0, 40.2)), Crs = new UnspecifiedCrs() - }); + });*/ /*Point point = new Point( @@ -993,13 +993,67 @@ public async Task ValidateSpatialPointJSONSerialization() ["battle"] = "a large abttle", ["cruise"] = "a new cruise" };*/ + /*Polygon polygon = new Polygon( + new[] + { + new LinearRing( + new[] + { + new Position(20, 20), + new Position(20, 21), + new Position(21, 21), + new Position(21, 20), + new Position(22, 20) + }) + }, + new GeometryParams + { + AdditionalProperties = new Dictionary { { "b", "c" } }, + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + });*/ + /*MultiPolygon multiPolygon = + new MultiPolygon( + new[] + { + new PolygonCoordinates( + new[] + { + new LinearRing( + new[] + { + new Position(20, 20), new Position(20, 21), new Position(21, 21), + new Position(21, 20), new Position(20, 20) + }) + }) + });*/ + + LineString lineString = new LineString( + new[] { new Position(20, 30), new Position(30, 40) }, + new GeometryParams + { + AdditionalProperties = new Dictionary { { "a", "b" } }, + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 41)), + Crs = Crs.Named("linestringCrs") + }); + GeometryCollection geometryCollection1 = new GeometryCollection( + new[] { lineString }, + new GeometryParams + { + AdditionalProperties = new Dictionary { { "a", "b" } }, + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + }); + /*GeometryCollection geometryCollection1 = new GeometryCollection( + new[] { new Point(20, 30), new Point(30, 40) } + );*/ SpatialItem inputItem = new SpatialItem() { Id = GUID, Name = "Spatial Point", - Location = point + Location = geometryCollection1 }; SpatialItem result = await container.CreateItemAsync(inputItem); @@ -1103,7 +1157,7 @@ internal record SpatialItem [JsonProperty("id")] public string Id { get; set; } public string Name { get; set; } - public Point Location { get; set; } + public GeometryCollection Location { get; set; } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs new file mode 100644 index 0000000000..544c796884 --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs @@ -0,0 +1,64 @@ +namespace Microsoft.Azure.Cosmos.Tests.Spatial +{ + using System; + using System.Collections.Generic; + using System.Text.Json; + using Microsoft.Azure.Cosmos.Spatial; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; + using Microsoft.VisualStudio.TestTools.UnitTesting; + + + /// + /// Tests class and serialization. + /// + [TestClass] + public class STJSpatialTest + { + /// + /// Tests serialization/deserialization. + /// + [TestMethod] + public void TestDictSerialization() + { + JsonSerializerOptions serializeOptions = new JsonSerializerOptions + { + Converters = + { + new DictionarySTJConverter() + } + }; + Dictionary input = new Dictionary + { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + }; + + string json = System.Text.Json.JsonSerializer.Serialize(input, serializeOptions); + + JsonSerializerOptions deserializeOptions = new JsonSerializerOptions(); + deserializeOptions.Converters.Add(new DictionarySTJConverter()); + + + Dictionary result = System.Text.Json.JsonSerializer.Deserialize>(json, serializeOptions); + Assert.AreEqual(input, result); + + /*Assert.AreEqual(2, point.Position.Coordinates.Count); + Assert.AreEqual(20.232323232323232, point.Position.Longitude); + Assert.AreEqual(30.3, point.Position.Latitude); + Assert.AreEqual(new Position(20, 20), point.BoundingBox.Min); + Assert.AreEqual(new Position(30, 30), point.BoundingBox.Max); + Assert.AreEqual("hello", ((NamedCrs)point.Crs).Name); + Assert.AreEqual(1, point.AdditionalProperties.Count); + Assert.AreEqual(1L, point.AdditionalProperties["extra"]); + + var geom = JsonConvert.DeserializeObject(json); + Assert.AreEqual(GeometryType.Point, geom.Type); + + Assert.AreEqual(geom, point); + + string json1 = JsonConvert.SerializeObject(point); + var geom1 = JsonConvert.DeserializeObject(json1); + Assert.AreEqual(geom1, geom);*/ + } + } +} From 3e9aa1ae184ae4a1b74a3f6243351491189caf21 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Fri, 1 Nov 2024 16:20:58 -0500 Subject: [PATCH 5/9] WIP: STJ Serialization/DeSerialization --- .../STJConverters/CrsSTJConverter.cs | 8 +- .../GeometryCollectionSTJConverter.cs | 51 +++- .../STJConverters/PointSTJConverter.cs | 8 +- .../src/Spatial/Geometry.cs | 2 + .../src/Spatial/GeometryParams.cs | 2 + Microsoft.Azure.Cosmos/src/Spatial/Point.cs | 14 +- .../src/Spatial/Position.cs | 27 +- .../ClientTests.cs | 93 +----- .../Spatial/PointTest.cs | 17 +- .../Spatial/STJSpatialTest.cs | 270 ++++++++++++++++-- 10 files changed, 340 insertions(+), 152 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs index 5a120c1982..7ac389db45 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs @@ -48,8 +48,12 @@ public override Crs Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSeri case "link": string crsHref = properties.GetProperty("href").GetString(); - string crsHrefType = properties.GetProperty("type").GetString(); - return new LinkedCrs(crsHref, crsHrefType); + if (properties.TryGetProperty("type", out JsonElement crsHrefType)) + { + return new LinkedCrs(crsHref, crsHrefType.GetString()); + } + //string crsHrefType = properties.GetProperty("type").GetString(); + return new LinkedCrs(crsHref); default: throw new JsonException(RMResources.SpatialFailedToDeserializeCrs); diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs index 97c738aa1b..8c82cf02f1 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs @@ -5,13 +5,12 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Drawing; using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; + using Microsoft.Azure.Cosmos.Serialization.HybridRow; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; using Point = Point; @@ -40,8 +39,50 @@ public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToCo geometries = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - Geometry geometry = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(geometry); + GeometryShape shape = (GeometryShape)arrayElement.GetProperty("type").GetInt16(); + Type type = shape.GetType(); + + switch (shape.ToString()) + { + case "Point": + Point point = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(point); + break; + + case "MultiPoint": + MultiPoint multiPoint = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(multiPoint); + break; + + case "LineString": + LineString lineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(lineString); + break; + + case "MultiLineString": + MultiLineString multiLineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(multiLineString); + break; + + case "Polygon": + Polygon polygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(polygon); + break; + + case "MultiPolygon": + MultiPolygon multiPolygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(multiPolygon); + break; + + case "GeometryCollection": + GeometryCollection geometryCollection = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(geometryCollection); + break; + + default: + throw new JsonException(RMResources.SpatialInvalidGeometryType); + + } } } else if (property.NameEquals("additionalProperties")) @@ -109,7 +150,7 @@ public override void Write(Utf8JsonWriter writer, GeometryCollection geometryCol { System.Text.Json.JsonSerializer.Serialize(writer, (GeometryCollection)geometry, options); } - + } writer.WriteEndArray(); diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs index 1fee7f4d34..6e5d40f2fb 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs @@ -88,15 +88,9 @@ public override void Write(Utf8JsonWriter writer, Point point, JsonSerializerOpt if (point.AdditionalProperties.Count > 0) { - //writer.WriteStartObject("additionalProperties"); writer.WritePropertyName("additionalProperties"); - /*foreach (KeyValuePair keyValue in point.AdditionalProperties) - { - writer.WritePropertyName(keyValue.Key); - System.Text.Json.JsonSerializer.Serialize(writer, keyValue.Value, options); - }*/ System.Text.Json.JsonSerializer.Serialize(writer, point.AdditionalProperties, options); - //writer.WriteEndObject(); + } writer.WriteEndObject(); diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs b/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs index e3ab8e2768..ca096ea71f 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs @@ -9,6 +9,7 @@ namespace Microsoft.Azure.Cosmos.Spatial using System.Linq; using System.Runtime.Serialization; using Microsoft.Azure.Cosmos.Spatial.Converters; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Microsoft.Azure.Documents; using Newtonsoft.Json; using Newtonsoft.Json.Converters; @@ -89,6 +90,7 @@ protected Geometry(GeometryType type, GeometryParams geometryParams) /// [JsonExtensionData] [DataMember(Name = "properties")] + [System.Text.Json.Serialization.JsonConverter(typeof(DictionarySTJConverter))] public IDictionary AdditionalProperties { get; private set; } /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs b/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs index 79877e3219..db4a7f1f32 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs @@ -6,6 +6,7 @@ namespace Microsoft.Azure.Cosmos.Spatial { using System.Collections.Generic; using System.Runtime.Serialization; + using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; /// /// Not frequently used geometry parameters in the Azure Cosmos DB service. @@ -20,6 +21,7 @@ public class GeometryParams /// Additional geometry properties. /// [DataMember(Name = "properties")] + [System.Text.Json.Serialization.JsonConverter(typeof(DictionarySTJConverter))] public IDictionary AdditionalProperties { get; set; } /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs index 79b19455c8..a70b1c86ff 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Point.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Point.cs @@ -53,7 +53,13 @@ public Point(Position position) public Point(Position position, GeometryParams geometryParams) : base(GeometryType.Point, geometryParams) { - this.Position = position ?? throw new ArgumentNullException("position"); + if (position == null) + { + throw new ArgumentNullException("position"); + } + + this.Position = position; + } /// @@ -73,8 +79,8 @@ internal Point() /// /// Coordinates of the point. /// - [DataMember(Name = PositionMetadataFields.Coordinates)] - [JsonProperty(PositionMetadataFields.Coordinates, Required = Required.Always, Order = 1)] + [DataMember(Name = "coordinates")] + [JsonProperty("coordinates", Required = Required.Always, Order = 1)] public Position Position { get; private set; } /// @@ -84,7 +90,7 @@ internal Point() /// true if objects are equal. false otherwise. public bool Equals(Point other) { - if (other is null) + if (object.ReferenceEquals(null, other)) { return false; } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs index 8cc1253f7e..131e0639f7 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Position.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Position.cs @@ -41,16 +41,6 @@ public Position(double longitude, double latitude) { } - /* - /// - /// Initializes a new instance of the class in the Azure Cosmos DB service. - /// - public Position() - : this(0.0d, 0.0d) - { - } - */ - /// /// Initializes a new instance of the class in the Azure Cosmos DB service. /// @@ -65,9 +55,15 @@ public Position() /// public Position(double longitude, double latitude, double? altitude) { - this.Coordinates = altitude != null - ? new ReadOnlyCollection(new[] { longitude, latitude, altitude.Value }) - : new ReadOnlyCollection(new[] { longitude, latitude }); + if (altitude != null) + { + this.Coordinates = new ReadOnlyCollection(new[] { longitude, latitude, altitude.Value }); + } + else + { + this.Coordinates = new ReadOnlyCollection(new[] { longitude, latitude }); + } + } /// @@ -101,7 +97,6 @@ public Position(IList coordinates) /// /// Longitude value. /// - [JsonProperty(PropertyName = PositionMetadataFields.Longitude, NullValueHandling = NullValueHandling.Ignore)] public double Longitude => this.Coordinates[0]; /// @@ -110,7 +105,6 @@ public Position(IList coordinates) /// /// Latitude value. /// - [JsonProperty(PropertyName = PositionMetadataFields.Latitude, NullValueHandling = NullValueHandling.Ignore)] public double Latitude => this.Coordinates[1]; /// @@ -119,7 +113,6 @@ public Position(IList coordinates) /// /// Altitude value. /// - [JsonProperty(PropertyName = PositionMetadataFields.Altitude, NullValueHandling = NullValueHandling.Ignore)] public double? Altitude => this.Coordinates.Count > 2 ? (double?)this.Coordinates[2] : null; /// @@ -155,7 +148,7 @@ public override int GetHashCode() /// true if objects are equal. false otherwise. public bool Equals(Position other) { - if (other is null) + if (object.ReferenceEquals(null, other)) { return false; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 230392381c..77db0c20f5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -953,107 +953,30 @@ public async Task ValidateSpatialPointJSONSerialization() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase } - })) + } + )) { string GUID = Guid.NewGuid().ToString(); Cosmos.Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync("AzureCosmosSpatialSerialization"); - Container container = await database.CreateContainerIfNotExistsAsync("spatial-items", "/id"); - /*Point point = new Point( + Point point = new Point( new Position(20, 30), new GeometryParams { - /*AdditionalProperties = new Dictionary { + AdditionalProperties = new Dictionary { ["battle"] = "a large abttle", ["cruise"] = "a new cruise" - },*/ - //BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), - //Crs = Crs.Named("SomeCrs") - //Crs = new UnspecifiedCrs() - //});*/ - /*Point point = new Point( - new Position(20.3, 30.5), - new GeometryParams - { - BoundingBox = new BoundingBox(new Position(1.0, 2.0), new Position(40.0, 40.2)), - Crs = new UnspecifiedCrs() - - });*/ - - - /*Point point = new Point( - new Position(20, 30) - );*/ - - - /*Dictionary dictionary = new Dictionary - { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" - };*/ - /*Polygon polygon = new Polygon( - new[] - { - new LinearRing( - new[] - { - new Position(20, 20), - new Position(20, 21), - new Position(21, 21), - new Position(21, 20), - new Position(22, 20) - }) - }, - new GeometryParams - { - AdditionalProperties = new Dictionary { { "b", "c" } }, - BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), - Crs = Crs.Named("SomeCrs") - });*/ - /*MultiPolygon multiPolygon = - new MultiPolygon( - new[] - { - new PolygonCoordinates( - new[] - { - new LinearRing( - new[] - { - new Position(20, 20), new Position(20, 21), new Position(21, 21), - new Position(21, 20), new Position(20, 20) - }) - }) - });*/ - - LineString lineString = new LineString( - new[] { new Position(20, 30), new Position(30, 40) }, - new GeometryParams - { - AdditionalProperties = new Dictionary { { "a", "b" } }, - BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 41)), - Crs = Crs.Named("linestringCrs") - }); - - GeometryCollection geometryCollection1 = new GeometryCollection( - new[] { lineString }, - new GeometryParams - { - AdditionalProperties = new Dictionary { { "a", "b" } }, - BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), - Crs = Crs.Named("SomeCrs") + }, + Crs = Crs.Linked("http://foo.com") }); - /*GeometryCollection geometryCollection1 = new GeometryCollection( - new[] { new Point(20, 30), new Point(30, 40) } - );*/ SpatialItem inputItem = new SpatialItem() { Id = GUID, Name = "Spatial Point", - Location = geometryCollection1 + Location = point }; SpatialItem result = await container.CreateItemAsync(inputItem); @@ -1157,7 +1080,7 @@ internal record SpatialItem [JsonProperty("id")] public string Id { get; set; } public string Name { get; set; } - public GeometryCollection Location { get; set; } + public Point Location { get; set; } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs index f40ed1f193..b99e73d68d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs @@ -25,7 +25,7 @@ public class PointTest [TestMethod] public void TestPointSerialization() { - string json = + /*string json = @"{ ""type"":""Point"", ""coordinates"":[20.232323232323232,30.3], @@ -50,7 +50,20 @@ public void TestPointSerialization() string json1 = JsonConvert.SerializeObject(point); var geom1 = JsonConvert.DeserializeObject(json1); - Assert.AreEqual(geom1, geom); + Assert.AreEqual(geom1, geom);*/ + Point point = new Point( + new Position(20, 30), + new GeometryParams + { + AdditionalProperties = new Dictionary { { "a", "b" } }, + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + //Crs = Crs.Linked("http://foo.com") + Crs = Crs.Linked("http://foo.com", "anotherType") + }); + string json = JsonConvert.SerializeObject(point); + Point geom = JsonConvert.DeserializeObject(json); + + Assert.AreEqual(geom, point); } /// diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs index 544c796884..86495bac07 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs @@ -1,64 +1,274 @@ -namespace Microsoft.Azure.Cosmos.Tests.Spatial +namespace Microsoft.Azure.Cosmos.Test.Spatial { - using System; using System.Collections.Generic; using System.Text.Json; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters; using Microsoft.VisualStudio.TestTools.UnitTesting; - + using Point = Cosmos.Spatial.Point; /// - /// Tests class and serialization. + /// Spatial STJ serialization/deserialization tests /// [TestClass] public class STJSpatialTest { /// - /// Tests serialization/deserialization. + /// Tests serialization/deserialization of Point class. /// [TestMethod] - public void TestDictSerialization() + [DynamicData(nameof(PointData))] + public void TestPointSerialization(Point input) { - JsonSerializerOptions serializeOptions = new JsonSerializerOptions + JsonSerializerOptions options = new JsonSerializerOptions { Converters = { new DictionarySTJConverter() } }; - Dictionary input = new Dictionary - { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" - }; + string json = JsonSerializer.Serialize(input, options); + Point result = JsonSerializer.Deserialize(json, options); + Assert.AreEqual(input, result); + } - string json = System.Text.Json.JsonSerializer.Serialize(input, serializeOptions); + /// + /// Tests serialization/deserialization of MultiPoint class. + /// + [TestMethod] + public void TestMultiPointSerialization() + { - JsonSerializerOptions deserializeOptions = new JsonSerializerOptions(); - deserializeOptions.Converters.Add(new DictionarySTJConverter()); + MultiPoint input = new MultiPoint( + new[] { new Position(20, 30), new Position(30, 40) }, + new GeometryParams + { + //AdditionalProperties = new Dictionary { { "a", "b" } }, + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + }); + + string json = JsonSerializer.Serialize(input); + MultiPoint result = JsonSerializer.Deserialize(json); + Assert.AreEqual(input, result); + } + /// + /// Tests serialization/deserialization of LineString class. + /// + [TestMethod] + [DynamicData(nameof(LineStringData))] + public void TestLineStringSerialization(LineString input) + { - Dictionary result = System.Text.Json.JsonSerializer.Deserialize>(json, serializeOptions); + string json = JsonSerializer.Serialize(input); + LineString result = JsonSerializer.Deserialize(json); Assert.AreEqual(input, result); + } - /*Assert.AreEqual(2, point.Position.Coordinates.Count); - Assert.AreEqual(20.232323232323232, point.Position.Longitude); - Assert.AreEqual(30.3, point.Position.Latitude); - Assert.AreEqual(new Position(20, 20), point.BoundingBox.Min); - Assert.AreEqual(new Position(30, 30), point.BoundingBox.Max); - Assert.AreEqual("hello", ((NamedCrs)point.Crs).Name); - Assert.AreEqual(1, point.AdditionalProperties.Count); - Assert.AreEqual(1L, point.AdditionalProperties["extra"]); + /// + /// Tests serialization/deserialization of MultiLineString class. + /// + [TestMethod] + public void TestMultiLineStringSerialization() + { + MultiLineString input = new MultiLineString( + new[] + { + new LineStringCoordinates(new[] { new Position(20, 30), new Position(30, 40) }), + new LineStringCoordinates(new[] { new Position(40, 50), new Position(60, 60) }) + }, + new GeometryParams + { + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + }); - var geom = JsonConvert.DeserializeObject(json); - Assert.AreEqual(GeometryType.Point, geom.Type); + string json = JsonSerializer.Serialize(input); + MultiLineString result = JsonSerializer.Deserialize(json); + Assert.AreEqual(input, result); + } - Assert.AreEqual(geom, point); + /// + /// Tests serialization/deserialization of Polygon class. + /// + [TestMethod] + [DynamicData(nameof(PolygonData))] + public void TestPolygonSerialization(Polygon input) + { - string json1 = JsonConvert.SerializeObject(point); - var geom1 = JsonConvert.DeserializeObject(json1); - Assert.AreEqual(geom1, geom);*/ + string json = JsonSerializer.Serialize(input); + Polygon result = JsonSerializer.Deserialize(json); + Assert.AreEqual(input, result); } + + /// + /// Tests serialization/deserialization of MultiPolygon class. + /// + [TestMethod] + [DynamicData(nameof(MultiPolygonData))] + public void TestMultiPolygonSerialization(MultiPolygon input) + { + + string json = JsonSerializer.Serialize(input); + MultiPolygon result = JsonSerializer.Deserialize(json); + Assert.AreEqual(input, result); + } + + /// + /// Tests serialization/deserialization of GeometryCollection class. + /// + [TestMethod] + public void TestGeometricCollectionSerialization() + { + GeometryCollection input = new GeometryCollection( + new[] { new Point(20, 30), new Point(30, 40) }, + new GeometryParams + { + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + }); + + + string json = JsonSerializer.Serialize(input); + GeometryCollection result = JsonSerializer.Deserialize(json); + Assert.AreEqual(input, result); + } + + public static IEnumerable PointData => new[] + { + new object[] { + new Point(new Position(20.4, 30.6)) + }, + new object[] { + new Point( + new Position(20, 30), + new GeometryParams + { + AdditionalProperties = new Dictionary { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + }, + }) + }, + new object[] { + new Point( + new Position(20, 30), + new GeometryParams + { + AdditionalProperties = new Dictionary { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + }, + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = new UnspecifiedCrs() + }) + }, + + + }; + + public static IEnumerable LineStringData => new[] + { + new object[] { + new LineString( + new[] { new Position(20, 30), new Position(30, 40) } + ) + }, + new object[] { + new LineString( + new[] { new Position(20, 30), new Position(30, 40) }, + new GeometryParams + { + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 41)), + }) + }, + new object[] { + new LineString( + new[] { new Position(20, 30), new Position(30, 40) }, + new GeometryParams + { + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 41)), + Crs = Crs.Linked("http://foo.com", "link") + }) + }, + + }; + + public static IEnumerable PolygonData => new[] + { + new object[] { + new Polygon( + new[]{ + new LinearRing( + new[]{ + new Position(20, 20), + new Position(20, 21), + new Position(21, 21), + new Position(21, 20), + new Position(22, 20) + }) + }) + }, + new object[] { + new Polygon( + new[]{ + new LinearRing( + new[]{ + new Position(20, 20), + new Position(20, 21), + new Position(21, 21), + new Position(21, 20), + new Position(22, 20) + }) + }, + new GeometryParams + { + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + }) + }, + new object[] { + new Polygon( + new[]{ + new LinearRing( + new[]{ + new Position(20, 20), + new Position(20, 21), + new Position(21, 21), + new Position(21, 20), + new Position(22, 20) + }) + }, + new GeometryParams + { + Crs = Crs.Named("SomeCrs") + }) + }, + }; + + public static IEnumerable MultiPolygonData => new[] + { + new object[] { + new MultiPolygon( + new[]{ + new PolygonCoordinates( + new[]{ + new LinearRing( + new[] + { + new Position(20, 20), new Position(20, 21), new Position(21, 21), + new Position(21, 20), new Position(20, 20) + }) + }) + }) + }, + + }; + + + + + } } From dbbcd69d9b88722cf415970acdb0737baeaeb219 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Mon, 4 Nov 2024 13:30:53 -0600 Subject: [PATCH 6/9] WIP: STJ Serialization/DeSerialization --- .../CosmosSystemTextJsonSerializer.cs | 3 +- .../STJConverters/BoundingBoxSTJConverter.cs | 36 ++++------ .../STJConverters/CrsSTJConverter.cs | 53 ++++++--------- .../STJConverters/DictionarySTJConverter.cs | 8 +-- .../GeometryCollectionSTJConverter.cs | 65 +++++++++---------- .../STJConverters/GeometryParamsHelper.cs | 15 ----- .../LineStringCoordinatesSTJConverter.cs | 24 ++----- .../STJConverters/LineStringSTJConverter.cs | 50 ++++---------- .../STJConverters/LinearRingSTJConverter.cs | 24 +++---- .../MultiLineStringSTJConverter.cs | 50 ++++---------- .../STJConverters/MultiPointSTJConverter.cs | 50 ++++---------- .../STJConverters/MultiPolygonSTJConverter.cs | 51 ++++----------- .../STJConverters/PointSTJConverter.cs | 55 +++++----------- .../PolygonCoordinatesSTJConverter.cs | 24 ++----- .../STJConverters/PolygonSTJConverter.cs | 50 ++++---------- .../STJConverters/PositionSTJConverter.cs | 29 ++------- .../STJConverters/STJMetaDataFields.cs | 41 ++++++++++++ .../Converters/STJConverters/SpatialHelper.cs | 36 ++++++++++ .../src/Spatial/PositionMetadataFields.cs | 19 ------ .../ClientTests.cs | 45 ++++++++++++- .../Spatial/PointTest.cs | 18 +---- .../Spatial/STJSpatialTest.cs | 47 +++++++++++++- 22 files changed, 349 insertions(+), 444 deletions(-) delete mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs create mode 100644 Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs delete mode 100644 Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs index f4fdaa30f0..0083742c23 100644 --- a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs +++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSystemTextJsonSerializer.cs @@ -30,7 +30,7 @@ internal CosmosSystemTextJsonSerializer( JsonSerializerOptions jsonSerializerOptions) { this.jsonSerializerOptions = jsonSerializerOptions; - //somehow adding a .NET native type converter as an attribute on properties doesnt take effect. In this case I tried adding it to AdditionalProperties of Geometry class. + //somehow adding a .NET native type converter(in this case Dictionary) as an attribute on properties doesnt take effect. So adding it here instead this.jsonSerializerOptions.Converters.Add(new DictionarySTJConverter()); } @@ -62,6 +62,7 @@ public override Stream ToStream(T input) { MemoryStream streamPayload = new (); using Utf8JsonWriter writer = new (streamPayload); + JsonSerializer.Serialize(writer, input, this.jsonSerializerOptions); streamPayload.Position = 0; diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs index 7bd120daed..5f282dddb4 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs @@ -5,23 +5,16 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Documents; - using static System.Text.Json.JsonElement; - + /// + /// Converter used to support System.Text.Json de/serialization of type BoundingBox/>. + /// internal class BoundingBoxSTJConverter : JsonConverter { public override BoundingBox Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -32,14 +25,14 @@ public override BoundingBox Read(ref Utf8JsonReader reader, Type typeToConvert, JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("min")) + if (property.NameEquals(STJMetaDataFields.Min)) { - min = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + min = JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("max")) + else if (property.NameEquals(STJMetaDataFields.Max)) { - max = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + max = JsonSerializer.Deserialize(property.Value.ToString(), options); } } @@ -49,19 +42,14 @@ public override BoundingBox Read(ref Utf8JsonReader reader, Type typeToConvert, public override void Write(Utf8JsonWriter writer, BoundingBox box, JsonSerializerOptions options) { - if (box == null) - { - return; - } - - writer.WriteStartObject("boundingBox"); + writer.WriteStartObject(STJMetaDataFields.BoundingBox); - writer.WriteStartObject("min"); - System.Text.Json.JsonSerializer.Serialize(writer, box.Min, options); + writer.WriteStartObject(STJMetaDataFields.Min); + JsonSerializer.Serialize(writer, box.Min, options); writer.WriteEndObject(); - writer.WriteStartObject("max"); - System.Text.Json.JsonSerializer.Serialize(writer, box.Max, options); + writer.WriteStartObject(STJMetaDataFields.Max); + JsonSerializer.Serialize(writer, box.Max, options); writer.WriteEndObject(); writer.WriteEndObject(); diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs index 7ac389db45..324020f78a 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/CrsSTJConverter.cs @@ -5,15 +5,12 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; - using Microsoft.Azure.Cosmos.Linq; using Microsoft.Azure.Documents; - using static System.Text.Json.JsonElement; - + /// + /// Converter used to support System.Text.Json de/serialization of type Crs/>. + /// internal class CrsSTJConverter : JsonConverter { public override Crs Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -22,19 +19,15 @@ public override Crs Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSeri { throw new JsonException(RMResources.JsonUnexpectedToken); } - if (reader.TokenType == JsonTokenType.Null) - { - return Crs.Unspecified; - } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; - JsonElement properties = rootElement.GetProperty("properties"); + JsonElement properties = rootElement.GetProperty(STJMetaDataFields.Properties); if (properties.ValueKind == JsonValueKind.Null || properties.ValueKind != JsonValueKind.Object) { throw new JsonException(RMResources.SpatialFailedToDeserializeCrs); } - JsonElement crsType = rootElement.GetProperty("type"); + JsonElement crsType = rootElement.GetProperty(STJMetaDataFields.Type); if (crsType.ValueKind == JsonValueKind.Null || crsType.ValueKind != JsonValueKind.String) { throw new JsonException(RMResources.SpatialFailedToDeserializeCrs); @@ -42,17 +35,16 @@ public override Crs Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSeri switch (crsType.GetString()) { - case "name": - string crsName = properties.GetProperty("name").GetString(); + case STJMetaDataFields.Name: + string crsName = properties.GetProperty(STJMetaDataFields.Name).GetString(); return new NamedCrs(crsName); - case "link": - string crsHref = properties.GetProperty("href").GetString(); - if (properties.TryGetProperty("type", out JsonElement crsHrefType)) + case STJMetaDataFields.Link: + string crsHref = properties.GetProperty(STJMetaDataFields.Href).GetString(); + if (properties.TryGetProperty(STJMetaDataFields.Type, out JsonElement crsHrefType)) { return new LinkedCrs(crsHref, crsHrefType.GetString()); } - //string crsHrefType = properties.GetProperty("type").GetString(); return new LinkedCrs(crsHref); default: @@ -62,23 +54,18 @@ public override Crs Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSeri } public override void Write(Utf8JsonWriter writer, Crs crs, JsonSerializerOptions options) { - if (crs == null) - { - return; - } - switch (crs.Type) { case CrsType.Linked: - writer.WriteStartObject("crs"); + writer.WriteStartObject(STJMetaDataFields.Crs); LinkedCrs linkedCrs = (LinkedCrs)crs; - writer.WriteString("type", "link"); - writer.WritePropertyName("properties"); + writer.WriteString(STJMetaDataFields.Type, STJMetaDataFields.Link); + writer.WritePropertyName(STJMetaDataFields.Properties); writer.WriteStartObject(); - writer.WriteString("href", linkedCrs.Href); + writer.WriteString(STJMetaDataFields.Href, linkedCrs.Href); if (linkedCrs.HrefType != null) { - writer.WriteString("type", linkedCrs.HrefType); + writer.WriteString(STJMetaDataFields.Type, linkedCrs.HrefType); } writer.WriteEndObject(); @@ -86,19 +73,19 @@ public override void Write(Utf8JsonWriter writer, Crs crs, JsonSerializerOptions break; case CrsType.Named: - writer.WriteStartObject("crs"); + writer.WriteStartObject(STJMetaDataFields.Crs); NamedCrs namedCrs = (NamedCrs)crs; - writer.WriteString("type", "name"); - writer.WritePropertyName("properties"); + writer.WriteString(STJMetaDataFields.Type, STJMetaDataFields.Name); + writer.WritePropertyName(STJMetaDataFields.Properties); writer.WriteStartObject(); - writer.WriteString("name", namedCrs.Name); + writer.WriteString(STJMetaDataFields.Name, namedCrs.Name); writer.WriteEndObject(); writer.WriteEndObject(); break; case CrsType.Unspecified: - writer.WriteNull("crs"); + writer.WriteNull(STJMetaDataFields.Crs); break; } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs index 67a5a4e314..10460ce6de 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs @@ -5,15 +5,11 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; - using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - // System.Text.Json by default returns JsonElement as value for a key in dictionary object as it cant infer the type of the value data. This Converter is required to property return .NET type instead of JsonElement back to the client. + // System.Text.Json by default returns JsonElement as a value type for any key in the dictionary as it cant infer the type of value data. This Converter is required to properly return .NET type instead of JsonElement back to the client. internal class DictionarySTJConverter : JsonConverter> { public override IDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -45,7 +41,7 @@ public override IDictionary Read(ref Utf8JsonReader reader, Type } public override void Write(Utf8JsonWriter writer, IDictionary dict, JsonSerializerOptions options) { - System.Text.Json.JsonSerializer.Serialize(writer, (Dictionary)dict, options); + JsonSerializer.Serialize(writer, (Dictionary)dict, options); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs index 8c82cf02f1..ab1fdf2040 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs @@ -6,23 +6,18 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; using System.Collections.Generic; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; - using Microsoft.Azure.Cosmos.Serialization.HybridRow; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; using Point = Point; - + /// + /// Converter used to support System.Text.Json de/serialization of type GeometryCollection/>. + /// internal class GeometryCollectionSTJConverter : JsonConverter { public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -34,7 +29,7 @@ public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToCo JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("geometries")) + if (property.NameEquals(STJMetaDataFields.Geometries)) { geometries = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) @@ -44,37 +39,37 @@ public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToCo switch (shape.ToString()) { - case "Point": + case nameof(GeometryShape.Point): Point point = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); geometries.Add(point); break; - case "MultiPoint": + case nameof(GeometryShape.MultiPoint): MultiPoint multiPoint = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); geometries.Add(multiPoint); break; - case "LineString": + case nameof(GeometryShape.LineString): LineString lineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); geometries.Add(lineString); break; - case "MultiLineString": + case nameof(GeometryShape.MultiLineString): MultiLineString multiLineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); geometries.Add(multiLineString); break; - case "Polygon": + case nameof(GeometryShape.Polygon): Polygon polygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); geometries.Add(polygon); break; - case "MultiPolygon": + case nameof(GeometryShape.MultiPolygon): MultiPolygon multiPolygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); geometries.Add(multiPolygon); break; - case "GeometryCollection": + case nameof(GeometryShape.GeometryCollection): GeometryCollection geometryCollection = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); geometries.Add(geometryCollection); break; @@ -85,21 +80,21 @@ public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToCo } } } - else if (property.NameEquals("additionalProperties")) + else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); Console.WriteLine(additionalProperties.ToString()); } - else if (property.NameEquals("crs")) + else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("boundingBox")) + else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); } @@ -114,47 +109,45 @@ public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToCo } public override void Write(Utf8JsonWriter writer, GeometryCollection geometryCollection, JsonSerializerOptions options) { - if (geometryCollection == null) - { - return; - } writer.WriteStartObject(); - writer.WriteStartArray("geometries"); + writer.WriteStartArray(STJMetaDataFields.Geometries); foreach (Geometry geometry in geometryCollection.Geometries) { if (geometry.GetType() == typeof(Point)) { - System.Text.Json.JsonSerializer.Serialize(writer, (Point)geometry, options); + JsonSerializer.Serialize(writer, (Point)geometry, options); } else if (geometry.GetType() == typeof(MultiPoint)) { - System.Text.Json.JsonSerializer.Serialize(writer, (MultiPoint)geometry, options); + JsonSerializer.Serialize(writer, (MultiPoint)geometry, options); } else if (geometry.GetType() == typeof(LineString)) { - System.Text.Json.JsonSerializer.Serialize(writer, (LineString)geometry, options); + JsonSerializer.Serialize(writer, (LineString)geometry, options); } else if (geometry.GetType() == typeof(MultiLineString)) { - System.Text.Json.JsonSerializer.Serialize(writer, (MultiLineString)geometry, options); + JsonSerializer.Serialize(writer, (MultiLineString)geometry, options); } else if (geometry.GetType() == typeof(Polygon)) { - System.Text.Json.JsonSerializer.Serialize(writer, (Polygon)geometry, options); + JsonSerializer.Serialize(writer, (Polygon)geometry, options); } else if (geometry.GetType() == typeof(MultiPolygon)) { - System.Text.Json.JsonSerializer.Serialize(writer, (MultiPolygon)geometry, options); + JsonSerializer.Serialize(writer, (MultiPolygon)geometry, options); } else if (geometry.GetType() == typeof(GeometryCollection)) { - System.Text.Json.JsonSerializer.Serialize(writer, (GeometryCollection)geometry, options); + JsonSerializer.Serialize(writer, (GeometryCollection)geometry, options); } } writer.WriteEndArray(); - System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.Crs, options); + + SpatialHelper.SerializePartialSpatialObject(geometryCollection.Crs, (int)geometryCollection.Type, geometryCollection.BoundingBox, geometryCollection.AdditionalProperties, writer, options); + /*System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.Crs, options); writer.WriteNumber("type", (int)geometryCollection.Type); if (geometryCollection.BoundingBox != null) { @@ -165,7 +158,7 @@ public override void Write(Utf8JsonWriter writer, GeometryCollection geometryCol writer.WritePropertyName("additionalProperties"); System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.AdditionalProperties, options); - } + }*/ writer.WriteEndObject(); diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs deleted file mode 100644 index a60a20f142..0000000000 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryParamsHelper.cs +++ /dev/null @@ -1,15 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// ------------------------------------------------------------ - -namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters -{ - using System; - using System.Collections.Generic; - using System.Text; - - internal class GeometryParamsHelper - { - //This a new file - } -} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs index da8fa7a292..923633d35b 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringCoordinatesSTJConverter.cs @@ -5,24 +5,18 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type LineStringCoordinates/>. + /// internal class LineStringCoordinatesSTJConverter : JsonConverter { public override LineStringCoordinates Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -31,12 +25,12 @@ public override LineStringCoordinates Read(ref Utf8JsonReader reader, Type typeT JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("positions")) + if (property.NameEquals(STJMetaDataFields.Positions)) { positions = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); positions.Add(pos); } } @@ -47,15 +41,11 @@ public override LineStringCoordinates Read(ref Utf8JsonReader reader, Type typeT } public override void Write(Utf8JsonWriter writer, LineStringCoordinates lineStringCorodinates, JsonSerializerOptions options) { - if (lineStringCorodinates == null) - { - return; - } - writer.WriteStartArray("positions"); + writer.WriteStartArray(STJMetaDataFields.Positions); foreach (Position position in lineStringCorodinates.Positions) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, position, options); + JsonSerializer.Serialize(writer, position, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs index a28dc67e12..9c038550b8 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs @@ -5,24 +5,18 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type LineString/>. + /// internal class LineStringSTJConverter : JsonConverter { public override LineString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -34,29 +28,29 @@ public override LineString Read(ref Utf8JsonReader reader, Type typeToConvert, J BoundingBox boundingBox = null; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("positions")) + if (property.NameEquals(STJMetaDataFields.Positions)) { positions = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); positions.Add(pos); } } - else if (property.NameEquals("additionalProperties")) + else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); } - else if (property.NameEquals("crs")) + else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("boundingBox")) + else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); } @@ -70,34 +64,18 @@ public override LineString Read(ref Utf8JsonReader reader, Type typeToConvert, J } public override void Write(Utf8JsonWriter writer, LineString lineString, JsonSerializerOptions options) { - if (lineString == null) - { - return; - } - writer.WriteStartObject(); - writer.WriteStartArray("positions"); + writer.WriteStartArray(STJMetaDataFields.Positions); foreach (Position position in lineString.Positions) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, position, options); + JsonSerializer.Serialize(writer, position, options); writer.WriteEndObject(); } writer.WriteEndArray(); - System.Text.Json.JsonSerializer.Serialize(writer, lineString.Crs, options); - writer.WriteNumber("type", (int)lineString.Type); - if (lineString.BoundingBox != null) - { - System.Text.Json.JsonSerializer.Serialize(writer, lineString.BoundingBox, options); - } - if (lineString.AdditionalProperties.Count > 0) - { - writer.WritePropertyName("additionalProperties"); - System.Text.Json.JsonSerializer.Serialize(writer, lineString.AdditionalProperties, options); - - } + SpatialHelper.SerializePartialSpatialObject(lineString.Crs, (int)lineString.Type, lineString.BoundingBox, lineString.AdditionalProperties, writer, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs index 1a37c5b243..fe38cbfc9e 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs @@ -5,24 +5,22 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type LinearRing/>. + /// internal class LinearRingSTJConverter : JsonConverter { public override LinearRing Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) + /*if (reader.TokenType == JsonTokenType.Null) { return null; - } + }*/ if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -31,12 +29,12 @@ public override LinearRing Read(ref Utf8JsonReader reader, Type typeToConvert, J JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("positions")) + if (property.NameEquals(STJMetaDataFields.Positions)) { positions = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); positions.Add(pos); } } @@ -47,15 +45,11 @@ public override LinearRing Read(ref Utf8JsonReader reader, Type typeToConvert, J } public override void Write(Utf8JsonWriter writer, LinearRing linearRing, JsonSerializerOptions options) { - if (linearRing == null) - { - return; - } - writer.WriteStartArray("positions"); + writer.WriteStartArray(STJMetaDataFields.Positions); foreach (Position position in linearRing.Positions) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, position, options); + JsonSerializer.Serialize(writer, position, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs index 2b85d94ffb..1fd246241f 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs @@ -5,23 +5,18 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; + /// + /// Converter used to support System.Text.Json de/serialization of type MultiLineString/>. + /// internal class MultiLineStringSTJConverter : JsonConverter { public override MultiLineString Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -33,30 +28,30 @@ public override MultiLineString Read(ref Utf8JsonReader reader, Type typeToConve BoundingBox boundingBox = null; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("lineStrings")) + if (property.NameEquals(STJMetaDataFields.LineStrings)) { coordinates = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - LineStringCoordinates lineStringCoordinate = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + LineStringCoordinates lineStringCoordinate = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); coordinates.Add(lineStringCoordinate); } } - else if (property.NameEquals("additionalProperties")) + else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); Console.WriteLine(additionalProperties.ToString()); } - else if (property.NameEquals("crs")) + else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("boundingBox")) + else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); } @@ -71,34 +66,17 @@ public override MultiLineString Read(ref Utf8JsonReader reader, Type typeToConve } public override void Write(Utf8JsonWriter writer, MultiLineString multiLineString, JsonSerializerOptions options) { - if (multiLineString == null) - { - return; - } - writer.WriteStartObject(); - writer.WriteStartArray("lineStrings"); + writer.WriteStartArray(STJMetaDataFields.LineStrings); foreach (LineStringCoordinates coordinates in multiLineString.LineStrings) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, coordinates, options); + JsonSerializer.Serialize(writer, coordinates, options); writer.WriteEndObject(); } writer.WriteEndArray(); - - System.Text.Json.JsonSerializer.Serialize(writer, multiLineString.Crs, options); - writer.WriteNumber("type", (int)multiLineString.Type); - if (multiLineString.BoundingBox != null) - { - System.Text.Json.JsonSerializer.Serialize(writer, multiLineString.BoundingBox, options); - } - if (multiLineString.AdditionalProperties.Count > 0) - { - writer.WritePropertyName("additionalProperties"); - System.Text.Json.JsonSerializer.Serialize(writer, multiLineString.AdditionalProperties, options); - - } + SpatialHelper.SerializePartialSpatialObject(multiLineString.Crs, (int)multiLineString.Type, multiLineString.BoundingBox, multiLineString.AdditionalProperties, writer, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs index e16b094e53..2802ce6952 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs @@ -5,24 +5,18 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type MultiPoint/>. + /// internal class MultiPointSTJConverter : JsonConverter { public override MultiPoint Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -34,30 +28,30 @@ public override MultiPoint Read(ref Utf8JsonReader reader, Type typeToConvert, J BoundingBox boundingBox = null; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("points")) + if (property.NameEquals(STJMetaDataFields.Points)) { positions = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - Position pos = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); positions.Add(pos); } } - else if (property.NameEquals("additionalProperties")) + else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); Console.WriteLine(additionalProperties.ToString()); } - else if (property.NameEquals("crs")) + else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("boundingBox")) + else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); } @@ -71,34 +65,18 @@ public override MultiPoint Read(ref Utf8JsonReader reader, Type typeToConvert, J } public override void Write(Utf8JsonWriter writer, MultiPoint multiPoint, JsonSerializerOptions options) { - if (multiPoint == null) - { - return; - } - writer.WriteStartObject(); - writer.WriteStartArray("points"); + writer.WriteStartArray(STJMetaDataFields.Points); foreach (Position position in multiPoint.Points) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, position, options); + JsonSerializer.Serialize(writer, position, options); writer.WriteEndObject(); } writer.WriteEndArray(); - System.Text.Json.JsonSerializer.Serialize(writer, multiPoint.Crs, options); - writer.WriteNumber("type", (int)multiPoint.Type); - if (multiPoint.BoundingBox != null) - { - System.Text.Json.JsonSerializer.Serialize(writer, multiPoint.BoundingBox, options); - } - if (multiPoint.AdditionalProperties.Count > 0) - { - writer.WritePropertyName("additionalProperties"); - System.Text.Json.JsonSerializer.Serialize(writer, multiPoint.AdditionalProperties, options); - - } + SpatialHelper.SerializePartialSpatialObject(multiPoint.Crs, (int)multiPoint.Type, multiPoint.BoundingBox, multiPoint.AdditionalProperties, writer, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs index 650be7cc78..1c82e94a0c 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs @@ -5,24 +5,19 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type MultiPolygon/>. + /// internal class MultiPolygonSTJConverter : JsonConverter { public override MultiPolygon Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -34,30 +29,30 @@ public override MultiPolygon Read(ref Utf8JsonReader reader, Type typeToConvert, BoundingBox boundingBox = null; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("polygons")) + if (property.NameEquals(STJMetaDataFields.Polygons)) { coordinates = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - PolygonCoordinates coordinate = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + PolygonCoordinates coordinate = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); coordinates.Add(coordinate); } } - else if (property.NameEquals("additionalProperties")) + else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); Console.WriteLine(additionalProperties.ToString()); } - else if (property.NameEquals("crs")) + else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("boundingBox")) + else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); } @@ -72,38 +67,20 @@ public override MultiPolygon Read(ref Utf8JsonReader reader, Type typeToConvert, } public override void Write(Utf8JsonWriter writer, MultiPolygon multiPolygon, JsonSerializerOptions options) { - if (multiPolygon == null) - { - return; - } - writer.WriteStartObject(); - writer.WriteStartArray("polygons"); + writer.WriteStartArray(STJMetaDataFields.Polygons); foreach (PolygonCoordinates coordinates in multiPolygon.Polygons) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, coordinates, options); + JsonSerializer.Serialize(writer, coordinates, options); writer.WriteEndObject(); } writer.WriteEndArray(); - System.Text.Json.JsonSerializer.Serialize(writer, multiPolygon.Crs, options); - writer.WriteNumber("type", (int)multiPolygon.Type); - if (multiPolygon.BoundingBox != null) - { - System.Text.Json.JsonSerializer.Serialize(writer, multiPolygon.BoundingBox, options); - } - if (multiPolygon.AdditionalProperties.Count > 0) - { - writer.WritePropertyName("additionalProperties"); - System.Text.Json.JsonSerializer.Serialize(writer, multiPolygon.AdditionalProperties, options); - - } - + SpatialHelper.SerializePartialSpatialObject(multiPolygon.Crs, (int)multiPolygon.Type, multiPolygon.BoundingBox, multiPolygon.AdditionalProperties, writer, options); writer.WriteEndObject(); } - } } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs index 6e5d40f2fb..3009ebcecf 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs @@ -5,53 +5,50 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; - using Antlr4.Runtime.Sharpen; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type Point/>. + /// internal class PointSTJConverter : JsonConverter { public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); } + JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; Position pos = null; IDictionary additionalProperties = null; Crs crs = null; BoundingBox boundingBox = null; + foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("position")) + if (property.NameEquals(STJMetaDataFields.Position)) { - pos = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + pos = JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("additionalProperties")) + else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); } - else if (property.NameEquals("crs")) + else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("boundingBox")) + else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); } @@ -66,33 +63,13 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe } public override void Write(Utf8JsonWriter writer, Point point, JsonSerializerOptions options) { - if (point == null) - { - return; - } - writer.WriteStartObject(); - writer.WriteStartObject("position"); - System.Text.Json.JsonSerializer.Serialize(writer, point.Position, options); + writer.WriteStartObject(STJMetaDataFields.Position); + JsonSerializer.Serialize(writer, point.Position, options); writer.WriteEndObject(); - System.Text.Json.JsonSerializer.Serialize(writer, point.Crs, options); - - writer.WriteNumber("type", (int)point.Type); - - if (point.BoundingBox != null) - { - System.Text.Json.JsonSerializer.Serialize(writer, point.BoundingBox, options); - } - - if (point.AdditionalProperties.Count > 0) - { - writer.WritePropertyName("additionalProperties"); - System.Text.Json.JsonSerializer.Serialize(writer, point.AdditionalProperties, options); - - } - + SpatialHelper.SerializePartialSpatialObject(point.Crs, (int)point.Type, point.BoundingBox, point.AdditionalProperties, writer, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs index 9b14d4a464..4c696a55ff 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonCoordinatesSTJConverter.cs @@ -5,24 +5,18 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type PolygonCoordinates/>. + /// internal class PolygonCoordinatesSTJConverter : JsonConverter { public override PolygonCoordinates Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -31,12 +25,12 @@ public override PolygonCoordinates Read(ref Utf8JsonReader reader, Type typeToCo JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("rings")) + if (property.NameEquals(STJMetaDataFields.Rings)) { linearRings = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - LinearRing ring = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + LinearRing ring = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); linearRings.Add(ring); } } @@ -47,15 +41,11 @@ public override PolygonCoordinates Read(ref Utf8JsonReader reader, Type typeToCo } public override void Write(Utf8JsonWriter writer, PolygonCoordinates polygonCoordinates, JsonSerializerOptions options) { - if (polygonCoordinates == null) - { - return; - } - writer.WriteStartArray("rings"); + writer.WriteStartArray(STJMetaDataFields.Rings); foreach (LinearRing ring in polygonCoordinates.Rings) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, ring, options); + JsonSerializer.Serialize(writer, ring, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs index 83e956f6b9..874a2c56a5 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs @@ -5,24 +5,19 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { using System; - using System.Collections; using System.Collections.Generic; - using System.Collections.ObjectModel; using System.Drawing; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Cosmos.Spatial; using Microsoft.Azure.Documents; - + /// + /// Converter used to support System.Text.Json de/serialization of type Polygon/>. + /// internal class PolygonSTJConverter : JsonConverter { public override Polygon Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -34,30 +29,30 @@ public override Polygon Read(ref Utf8JsonReader reader, Type typeToConvert, Json BoundingBox boundingBox = null; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals("rings")) + if (property.NameEquals(STJMetaDataFields.Rings)) { linearRings = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) { - LinearRing linearRing = System.Text.Json.JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + LinearRing linearRing = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); linearRings.Add(linearRing); } } - else if (property.NameEquals("additionalProperties")) + else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = System.Text.Json.JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); Console.WriteLine(additionalProperties.ToString()); } - else if (property.NameEquals("crs")) + else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.ToString(), options); } - else if (property.NameEquals("boundingBox")) + else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = System.Text.Json.JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); } @@ -72,35 +67,18 @@ public override Polygon Read(ref Utf8JsonReader reader, Type typeToConvert, Json } public override void Write(Utf8JsonWriter writer, Polygon polygon, JsonSerializerOptions options) { - if (polygon == null) - { - return; - } - writer.WriteStartObject(); - writer.WriteStartArray("rings"); + writer.WriteStartArray(STJMetaDataFields.Rings); foreach (LinearRing linearRing in polygon.Rings) { writer.WriteStartObject(); - System.Text.Json.JsonSerializer.Serialize(writer, linearRing, options); + JsonSerializer.Serialize(writer, linearRing, options); writer.WriteEndObject(); } writer.WriteEndArray(); - System.Text.Json.JsonSerializer.Serialize(writer, polygon.Crs, options); - writer.WriteNumber("type", (int)polygon.Type); - if (polygon.BoundingBox != null) - { - System.Text.Json.JsonSerializer.Serialize(writer, polygon.BoundingBox, options); - } - if (polygon.AdditionalProperties.Count > 0) - { - writer.WritePropertyName("additionalProperties"); - System.Text.Json.JsonSerializer.Serialize(writer, polygon.AdditionalProperties, options); - - } - + SpatialHelper.SerializePartialSpatialObject(polygon.Crs, (int)polygon.Type, polygon.BoundingBox, polygon.AdditionalProperties, writer, options); writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJConverter.cs index bcdc652ec9..d7ecacbdc1 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PositionSTJConverter.cs @@ -7,12 +7,9 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters using System; using System.Collections.Generic; using System.Collections.ObjectModel; - using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Documents; - using static System.Text.Json.JsonElement; - /// /// Converter used to support System.Text.Json de/serialization of type Position/>. /// @@ -20,10 +17,6 @@ internal class PositionSTJConverter : JsonConverter { public override Position Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - if (reader.TokenType == JsonTokenType.Null) - { - return null; - } if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); @@ -32,7 +25,7 @@ public override Position Read(ref Utf8JsonReader reader, Type typeToConvert, Jso JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; foreach (JsonProperty property in rootElement.EnumerateObject()) { - if (property.NameEquals(PositionMetadataFields.Coordinates)) + if (property.NameEquals(STJMetaDataFields.Coordinates)) { IList coordinates = new List(); foreach (JsonElement arrayElement in property.Value.EnumerateArray()) @@ -41,7 +34,6 @@ public override Position Read(ref Utf8JsonReader reader, Type typeToConvert, Jso } return new Position(new ReadOnlyCollection(coordinates)); - } } @@ -50,14 +42,7 @@ public override Position Read(ref Utf8JsonReader reader, Type typeToConvert, Jso } public override void Write(Utf8JsonWriter writer, Position position, JsonSerializerOptions options) { - if (position == null) - { - return; - } - - //writer.WriteStartObject("position"); - - writer.WriteStartArray(PositionMetadataFields.Coordinates); + writer.WriteStartArray(STJMetaDataFields.Coordinates); writer.WriteNumberValue(position.Longitude); writer.WriteNumberValue(position.Latitude); if (position.Altitude.HasValue) @@ -65,19 +50,17 @@ public override void Write(Utf8JsonWriter writer, Position position, JsonSeriali writer.WriteNumberValue(position.Altitude.Value); } writer.WriteEndArray(); - writer.WriteNumber(PositionMetadataFields.Longitude, position.Longitude); - writer.WriteNumber(PositionMetadataFields.Latitude, position.Latitude); + writer.WriteNumber(STJMetaDataFields.Longitude, position.Longitude); + writer.WriteNumber(STJMetaDataFields.Latitude, position.Latitude); if (position.Altitude.HasValue) { - writer.WriteNumber(PositionMetadataFields.Altitude, position.Altitude.Value); + writer.WriteNumber(STJMetaDataFields.Altitude, position.Altitude.Value); } else { - writer.WriteNull(PositionMetadataFields.Altitude); + writer.WriteNull(STJMetaDataFields.Altitude); } - //writer.WriteEndObject(); - } } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs new file mode 100644 index 0000000000..8e432c35c3 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs @@ -0,0 +1,41 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections.Generic; + using System.Text; + + internal class STJMetaDataFields + { + private STJMetaDataFields() + { + throw new InvalidOperationException(" cannot instantitate utility class. use it as static reference"); + } + + public const string Position = "position"; + public const string AdditionalProperties = "additionalProperties"; + public const string Crs = "crs"; + public const string BoundingBox = "boundingBox"; + public const string Type = "type"; + public const string Points = "points"; + public const string Positions = "positions"; + public const string LineStrings = "lineStrings"; + public const string Rings = "rings"; + public const string Polygons = "polygons"; + public const string Max = "max"; + public const string Min = "min"; + public const string Properties = "properties"; + public const string Name = "name"; + public const string Link = "link"; + public const string Href = "href"; + public const string Geometries = "geometries"; + public const string Longitude = "longitude"; + public const string Altitude = "altitude"; + public const string Latitude = "latitude"; + public const string Coordinates = "coordinates"; + + } +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs new file mode 100644 index 0000000000..2bff169c99 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs @@ -0,0 +1,36 @@ +// ------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// ------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Drawing; + using System.Text.Json; + + internal static class SpatialHelper + { + public static void SerializePartialSpatialObject(Crs crs, int spatialType, BoundingBox boundingBox, IDictionary additionalProperties, + Utf8JsonWriter writer, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, crs, options); + writer.WriteNumber(STJMetaDataFields.Type, spatialType); + + if (boundingBox != null) + { + JsonSerializer.Serialize(writer, boundingBox, options); + } + + if (additionalProperties.Count > 0) + { + writer.WritePropertyName(STJMetaDataFields.AdditionalProperties); + System.Text.Json.JsonSerializer.Serialize(writer, additionalProperties, options); + } + + } + + } + +} diff --git a/Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs b/Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs deleted file mode 100644 index 5a3cd2e5f4..0000000000 --- a/Microsoft.Azure.Cosmos/src/Spatial/PositionMetadataFields.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// ------------------------------------------------------------ - -namespace Microsoft.Azure.Cosmos.Spatial -{ - using System; - using System.Collections.Generic; - using System.Text; - - internal class PositionMetadataFields - { - public const string Latitude = "latitude"; - public const string Longitude = "longitude"; - public const string Altitude = "altitude"; - public const string Coordinates = "coordinates"; - - } -} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 77db0c20f5..801db01f68 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -941,7 +941,7 @@ public async Task MultiRegionAccountTest() } [TestMethod] - public async Task ValidateSpatialPointJSONSerialization() + public async Task ValidateSpatialPointSTJSerialization() { string authKey = ConfigurationManager.AppSettings["MasterKey"]; string endpoint = ConfigurationManager.AppSettings["GatewayEndpoint"]; @@ -949,6 +949,7 @@ public async Task ValidateSpatialPointJSONSerialization() using (CosmosClient cosmosClient = new CosmosClient(endpoint, authKey, new CosmosClientOptions() { + // this makes it use STJ library for serialization/de-serialization UseSystemTextJsonSerializerWithOptions = new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase @@ -969,7 +970,47 @@ public async Task ValidateSpatialPointJSONSerialization() ["battle"] = "a large abttle", ["cruise"] = "a new cruise" }, - Crs = Crs.Linked("http://foo.com") + Crs = Crs.Linked("http://foo.com", "link") + }); + + SpatialItem inputItem = new SpatialItem() + { + Id = GUID, + Name = "Spatial Point", + Location = point + }; + + SpatialItem result = await container.CreateItemAsync(inputItem); + SpatialItem readItem = await container.ReadItemAsync(GUID, new Cosmos.PartitionKey(GUID)); + + Assert.AreEqual(readItem, inputItem); + Assert.AreEqual(result, inputItem); + } + + } + [TestMethod] + public async Task ValidateSpatialPointNewtonSoftSerialization() + { + string authKey = ConfigurationManager.AppSettings["MasterKey"]; + string endpoint = ConfigurationManager.AppSettings["GatewayEndpoint"]; + // default serialization uses NewtonSoft + using (CosmosClient cosmosClient = new CosmosClient(endpoint, authKey)) + { + + string GUID = Guid.NewGuid().ToString(); + Cosmos.Database database = await cosmosClient.CreateDatabaseIfNotExistsAsync("AzureCosmosSpatialSerialization"); + Container container = await database.CreateContainerIfNotExistsAsync("spatial-items", "/id"); + + Point point = new Point( + new Position(20, 30), + new GeometryParams + { + AdditionalProperties = new Dictionary + { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + }, + Crs = Crs.Linked("http://foo.com", "link") }); SpatialItem inputItem = new SpatialItem() diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs index b99e73d68d..957d00d37b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs @@ -25,7 +25,7 @@ public class PointTest [TestMethod] public void TestPointSerialization() { - /*string json = + string json = @"{ ""type"":""Point"", ""coordinates"":[20.232323232323232,30.3], @@ -50,20 +50,8 @@ public void TestPointSerialization() string json1 = JsonConvert.SerializeObject(point); var geom1 = JsonConvert.DeserializeObject(json1); - Assert.AreEqual(geom1, geom);*/ - Point point = new Point( - new Position(20, 30), - new GeometryParams - { - AdditionalProperties = new Dictionary { { "a", "b" } }, - BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), - //Crs = Crs.Linked("http://foo.com") - Crs = Crs.Linked("http://foo.com", "anotherType") - }); - string json = JsonConvert.SerializeObject(point); - Point geom = JsonConvert.DeserializeObject(json); - - Assert.AreEqual(geom, point); + Assert.AreEqual(geom1, geom); + } /// diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs index 86495bac07..d4cf2156f6 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs @@ -43,7 +43,6 @@ public void TestMultiPointSerialization() new[] { new Position(20, 30), new Position(30, 40) }, new GeometryParams { - //AdditionalProperties = new Dictionary { { "a", "b" } }, BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), Crs = Crs.Named("SomeCrs") }); @@ -164,6 +163,30 @@ public void TestGeometricCollectionSerialization() Crs = new UnspecifiedCrs() }) }, + new object[] { + new Point( + new Position(20, 30), + new GeometryParams + { + AdditionalProperties = new Dictionary { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + }, + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + }) + }, + new object[] { + new Point( + new Position(20, 30), + new GeometryParams + { + AdditionalProperties = new Dictionary { + ["battle"] = "a large abttle", + ["cruise"] = "a new cruise" + }, + Crs = new UnspecifiedCrs() + }) + } }; @@ -264,6 +287,28 @@ public void TestGeometricCollectionSerialization() }) }, + new object[] { + new MultiPolygon( + new[] + { + new PolygonCoordinates( + new[] + { + new LinearRing( + new[] + { + new Position(20, 21), new Position(20, 21), new Position(21, 21), + new Position(21, 20), new Position(22, 20) + }) + }) + }, + new GeometryParams + { + BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), + Crs = Crs.Named("SomeCrs") + }) + }, + }; From 1cdb6f4436de63da5b414d7053c60acd93449886 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Mon, 4 Nov 2024 15:30:58 -0600 Subject: [PATCH 7/9] WIP: STJ Serialization/DeSerialization --- .../STJConverters/BoundingBoxSTJConverter.cs | 5 ++--- .../GeometryCollectionSTJConverter.cs | 19 +++---------------- .../STJConverters/LineStringSTJConverter.cs | 6 +++--- .../MultiLineStringSTJConverter.cs | 6 +++--- .../STJConverters/MultiPointSTJConverter.cs | 6 +++--- .../STJConverters/MultiPolygonSTJConverter.cs | 6 +++--- .../STJConverters/PointSTJConverter.cs | 8 ++++---- .../STJConverters/PolygonSTJConverter.cs | 7 +++---- .../Converters/STJConverters/SpatialHelper.cs | 5 +---- 9 files changed, 25 insertions(+), 43 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs index 5f282dddb4..4851094d66 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/BoundingBoxSTJConverter.cs @@ -27,12 +27,11 @@ public override BoundingBox Read(ref Utf8JsonReader reader, Type typeToConvert, { if (property.NameEquals(STJMetaDataFields.Min)) { - min = JsonSerializer.Deserialize(property.Value.ToString(), options); - + min = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.Max)) { - max = JsonSerializer.Deserialize(property.Value.ToString(), options); + max = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs index ab1fdf2040..add821f284 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs @@ -82,19 +82,19 @@ public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToCo } else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); Console.WriteLine(additionalProperties.ToString()); } else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } @@ -147,19 +147,6 @@ public override void Write(Utf8JsonWriter writer, GeometryCollection geometryCol writer.WriteEndArray(); SpatialHelper.SerializePartialSpatialObject(geometryCollection.Crs, (int)geometryCollection.Type, geometryCollection.BoundingBox, geometryCollection.AdditionalProperties, writer, options); - /*System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.Crs, options); - writer.WriteNumber("type", (int)geometryCollection.Type); - if (geometryCollection.BoundingBox != null) - { - System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.BoundingBox, options); - } - if (geometryCollection.AdditionalProperties.Count > 0) - { - writer.WritePropertyName("additionalProperties"); - System.Text.Json.JsonSerializer.Serialize(writer, geometryCollection.AdditionalProperties, options); - - }*/ - writer.WriteEndObject(); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs index 9c038550b8..f5374de513 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs @@ -39,18 +39,18 @@ public override LineString Read(ref Utf8JsonReader reader, Type typeToConvert, J } else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs index 1fd246241f..7b77683f25 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs @@ -39,19 +39,19 @@ public override MultiLineString Read(ref Utf8JsonReader reader, Type typeToConve } else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); Console.WriteLine(additionalProperties.ToString()); } else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs index 2802ce6952..3eaea006f6 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs @@ -39,19 +39,19 @@ public override MultiPoint Read(ref Utf8JsonReader reader, Type typeToConvert, J } else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); Console.WriteLine(additionalProperties.ToString()); } else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs index 1c82e94a0c..a8e00083bc 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs @@ -40,19 +40,19 @@ public override MultiPolygon Read(ref Utf8JsonReader reader, Type typeToConvert, } else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); Console.WriteLine(additionalProperties.ToString()); } else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs index 3009ebcecf..abbd186b8e 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs @@ -32,23 +32,23 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe { if (property.NameEquals(STJMetaDataFields.Position)) { - pos = JsonSerializer.Deserialize(property.Value.ToString(), options); + pos = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); + additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs index 874a2c56a5..89ad61627c 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs @@ -40,19 +40,18 @@ public override Polygon Read(ref Utf8JsonReader reader, Type typeToConvert, Json } else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) { - additionalProperties = JsonSerializer.Deserialize>(property.Value.ToString(), options); - Console.WriteLine(additionalProperties.ToString()); + additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.Crs)) { crs = property.Value.ValueKind == JsonValueKind.Null ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.ToString(), options); + : JsonSerializer.Deserialize(property.Value.GetRawText(), options); } else if (property.NameEquals(STJMetaDataFields.BoundingBox)) { - boundingBox = JsonSerializer.Deserialize(property.Value.ToString(), options); + boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); } diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs index 2bff169c99..e72e01ef15 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs @@ -4,10 +4,7 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters { - using System; using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Drawing; using System.Text.Json; internal static class SpatialHelper @@ -26,7 +23,7 @@ public static void SerializePartialSpatialObject(Crs crs, int spatialType, Bound if (additionalProperties.Count > 0) { writer.WritePropertyName(STJMetaDataFields.AdditionalProperties); - System.Text.Json.JsonSerializer.Serialize(writer, additionalProperties, options); + JsonSerializer.Serialize(writer, additionalProperties, options); } } From 4332bcdb8635563441d6cc2a65d3d41560926205 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Mon, 4 Nov 2024 15:34:08 -0600 Subject: [PATCH 8/9] WIP: STJ Serialization/DeSerialization --- Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs | 1 - Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs b/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs index ca096ea71f..03606fbd6b 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Geometry.cs @@ -90,7 +90,6 @@ protected Geometry(GeometryType type, GeometryParams geometryParams) /// [JsonExtensionData] [DataMember(Name = "properties")] - [System.Text.Json.Serialization.JsonConverter(typeof(DictionarySTJConverter))] public IDictionary AdditionalProperties { get; private set; } /// diff --git a/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs b/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs index db4a7f1f32..6efab2d43e 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/GeometryParams.cs @@ -21,7 +21,6 @@ public class GeometryParams /// Additional geometry properties. /// [DataMember(Name = "properties")] - [System.Text.Json.Serialization.JsonConverter(typeof(DictionarySTJConverter))] public IDictionary AdditionalProperties { get; set; } /// From 72538c76edb290a11f1234b1fd6da486f85d9e49 Mon Sep 17 00:00:00 2001 From: Dikshi Bahl Date: Tue, 5 Nov 2024 10:29:10 -0600 Subject: [PATCH 9/9] WIP: STJ Serialization/DeSerialization --- .../STJConverters/DictionarySTJConverter.cs | 3 +- .../GeometryCollectionSTJConverter.cs | 116 +++++++----------- .../STJConverters/LineStringSTJConverter.cs | 34 ++--- .../STJConverters/LinearRingSTJConverter.cs | 4 - .../MultiLineStringSTJConverter.cs | 36 ++---- .../STJConverters/MultiPointSTJConverter.cs | 38 ++---- .../STJConverters/MultiPolygonSTJConverter.cs | 36 ++---- .../STJConverters/PointSTJConverter.cs | 30 +---- .../STJConverters/PolygonSTJConverter.cs | 36 ++---- .../STJConverters/STJMetaDataFields.cs | 7 +- .../Converters/STJConverters/SpatialHelper.cs | 26 ++++ .../ClientTests.cs | 9 +- .../Spatial/PointTest.cs | 1 - .../Spatial/STJSpatialTest.cs | 22 ++-- 14 files changed, 134 insertions(+), 264 deletions(-) diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs index 10460ce6de..d8406806f1 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/DictionarySTJConverter.cs @@ -9,7 +9,7 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters using System.Text.Json; using System.Text.Json.Serialization; using Microsoft.Azure.Documents; - // System.Text.Json by default returns JsonElement as a value type for any key in the dictionary as it cant infer the type of value data. This Converter is required to properly return .NET type instead of JsonElement back to the client. + // System.Text.Json by default returns JsonElement as a value type for any key in the dictionary as it cant infer the type of value . This Converter is required to translate JsonElement to .NET type to return back to the client. internal class DictionarySTJConverter : JsonConverter> { public override IDictionary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -53,6 +53,7 @@ JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => dateti JsonTokenType.String => reader.GetString(), JsonTokenType.True => true, JsonTokenType.False => false, + JsonTokenType.Number when reader.TryGetInt32(out int i) => i, JsonTokenType.Number when reader.TryGetInt64(out long l) => l, JsonTokenType.Number => reader.GetDouble(), JsonTokenType.Null => null, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs index add821f284..b93bbd7ef6 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/GeometryCollectionSTJConverter.cs @@ -23,82 +23,60 @@ public override GeometryCollection Read(ref Utf8JsonReader reader, Type typeToCo throw new JsonException(RMResources.JsonUnexpectedToken); } IList geometries = null; - IDictionary additionalProperties = null; - Crs crs = null; - BoundingBox boundingBox = null; JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; - foreach (JsonProperty property in rootElement.EnumerateObject()) + if (rootElement.TryGetProperty(STJMetaDataFields.Geometries, out JsonElement value)) { - if (property.NameEquals(STJMetaDataFields.Geometries)) + geometries = new List(); + foreach (JsonElement arrayElement in value.EnumerateArray()) { - geometries = new List(); - foreach (JsonElement arrayElement in property.Value.EnumerateArray()) - { - GeometryShape shape = (GeometryShape)arrayElement.GetProperty("type").GetInt16(); - Type type = shape.GetType(); - - switch (shape.ToString()) - { - case nameof(GeometryShape.Point): - Point point = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(point); - break; - - case nameof(GeometryShape.MultiPoint): - MultiPoint multiPoint = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(multiPoint); - break; - - case nameof(GeometryShape.LineString): - LineString lineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(lineString); - break; - - case nameof(GeometryShape.MultiLineString): - MultiLineString multiLineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(multiLineString); - break; - - case nameof(GeometryShape.Polygon): - Polygon polygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(polygon); - break; - - case nameof(GeometryShape.MultiPolygon): - MultiPolygon multiPolygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(multiPolygon); - break; - - case nameof(GeometryShape.GeometryCollection): - GeometryCollection geometryCollection = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - geometries.Add(geometryCollection); - break; - - default: - throw new JsonException(RMResources.SpatialInvalidGeometryType); - - } - } - } - else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) - { - additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); - Console.WriteLine(additionalProperties.ToString()); - } - else if (property.NameEquals(STJMetaDataFields.Crs)) - { - crs = property.Value.ValueKind == JsonValueKind.Null - ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.GetRawText(), options); + GeometryShape shape = (GeometryShape)arrayElement.GetProperty("type").GetInt16(); + Type type = shape.GetType(); - } - else if (property.NameEquals(STJMetaDataFields.BoundingBox)) - { - boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); + switch (shape.ToString()) + { + case nameof(GeometryShape.Point): + Point point = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(point); + break; + + case nameof(GeometryShape.MultiPoint): + MultiPoint multiPoint = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(multiPoint); + break; + + case nameof(GeometryShape.LineString): + LineString lineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(lineString); + break; + + case nameof(GeometryShape.MultiLineString): + MultiLineString multiLineString = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(multiLineString); + break; + + case nameof(GeometryShape.Polygon): + Polygon polygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(polygon); + break; + + case nameof(GeometryShape.MultiPolygon): + MultiPolygon multiPolygon = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(multiPolygon); + break; + + case nameof(GeometryShape.GeometryCollection): + GeometryCollection geometryCollection = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + geometries.Add(geometryCollection); + break; + + default: + throw new JsonException(RMResources.SpatialInvalidGeometryType); + } } - } + + (IDictionary additionalProperties, Crs crs, BoundingBox boundingBox) = SpatialHelper.DeSerializePartialSpatialObject(rootElement, options); return new GeometryCollection(geometries, new GeometryParams { AdditionalProperties = additionalProperties, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs index f5374de513..df59ed7185 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LineStringSTJConverter.cs @@ -23,38 +23,18 @@ public override LineString Read(ref Utf8JsonReader reader, Type typeToConvert, J } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; IList positions = null; - IDictionary additionalProperties = null; - Crs crs = null; - BoundingBox boundingBox = null; - foreach (JsonProperty property in rootElement.EnumerateObject()) + if (rootElement.TryGetProperty(STJMetaDataFields.Positions, out JsonElement value)) { - if (property.NameEquals(STJMetaDataFields.Positions)) + positions = new List(); + foreach (JsonElement arrayElement in value.EnumerateArray()) { - positions = new List(); - foreach (JsonElement arrayElement in property.Value.EnumerateArray()) - { - Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - positions.Add(pos); - } + Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + positions.Add(pos); } - else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) - { - additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); - } - else if (property.NameEquals(STJMetaDataFields.Crs)) - { - crs = property.Value.ValueKind == JsonValueKind.Null - ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.GetRawText(), options); - - } - else if (property.NameEquals(STJMetaDataFields.BoundingBox)) - { - boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); + } - } + (IDictionary additionalProperties, Crs crs, BoundingBox boundingBox) = SpatialHelper.DeSerializePartialSpatialObject(rootElement, options); - } return new LineString(positions, new GeometryParams { AdditionalProperties = additionalProperties, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs index fe38cbfc9e..2eaf35cf1a 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/LinearRingSTJConverter.cs @@ -17,10 +17,6 @@ internal class LinearRingSTJConverter : JsonConverter { public override LinearRing Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { - /*if (reader.TokenType == JsonTokenType.Null) - { - return null; - }*/ if (reader.TokenType != JsonTokenType.StartObject) { throw new JsonException(RMResources.JsonUnexpectedToken); diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs index 7b77683f25..f6dc36bc86 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiLineStringSTJConverter.cs @@ -23,39 +23,19 @@ public override MultiLineString Read(ref Utf8JsonReader reader, Type typeToConve } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; IList coordinates = null; - IDictionary additionalProperties = null; - Crs crs = null; - BoundingBox boundingBox = null; - foreach (JsonProperty property in rootElement.EnumerateObject()) + + if (rootElement.TryGetProperty(STJMetaDataFields.LineStrings, out JsonElement value)) { - if (property.NameEquals(STJMetaDataFields.LineStrings)) - { - coordinates = new List(); - foreach (JsonElement arrayElement in property.Value.EnumerateArray()) - { - LineStringCoordinates lineStringCoordinate = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - coordinates.Add(lineStringCoordinate); - } - } - else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) - { - additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); - Console.WriteLine(additionalProperties.ToString()); - } - else if (property.NameEquals(STJMetaDataFields.Crs)) + coordinates = new List(); + foreach (JsonElement arrayElement in value.EnumerateArray()) { - crs = property.Value.ValueKind == JsonValueKind.Null - ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.GetRawText(), options); - + LineStringCoordinates lineStringCoordinate = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + coordinates.Add(lineStringCoordinate); } - else if (property.NameEquals(STJMetaDataFields.BoundingBox)) - { - boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); + } - } + (IDictionary additionalProperties, Crs crs, BoundingBox boundingBox) = SpatialHelper.DeSerializePartialSpatialObject(rootElement, options); - } return new MultiLineString(coordinates, new GeometryParams { AdditionalProperties = additionalProperties, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs index 3eaea006f6..5b1bbd21ee 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPointSTJConverter.cs @@ -23,39 +23,19 @@ public override MultiPoint Read(ref Utf8JsonReader reader, Type typeToConvert, J } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; IList positions = null; - IDictionary additionalProperties = null; - Crs crs = null; - BoundingBox boundingBox = null; - foreach (JsonProperty property in rootElement.EnumerateObject()) - { - if (property.NameEquals(STJMetaDataFields.Points)) - { - positions = new List(); - foreach (JsonElement arrayElement in property.Value.EnumerateArray()) - { - Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - positions.Add(pos); - } - } - else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) - { - additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); - Console.WriteLine(additionalProperties.ToString()); - } - else if (property.NameEquals(STJMetaDataFields.Crs)) - { - crs = property.Value.ValueKind == JsonValueKind.Null - ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.GetRawText(), options); - } - else if (property.NameEquals(STJMetaDataFields.BoundingBox)) + if (rootElement.TryGetProperty(STJMetaDataFields.Points, out JsonElement value)) + { + positions = new List(); + foreach (JsonElement arrayElement in value.EnumerateArray()) { - boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); - + Position pos = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + positions.Add(pos); } - } + + (IDictionary additionalProperties, Crs crs, BoundingBox boundingBox) = SpatialHelper.DeSerializePartialSpatialObject(rootElement, options); + return new MultiPoint(positions, new GeometryParams { AdditionalProperties = additionalProperties, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs index a8e00083bc..24b5104f94 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/MultiPolygonSTJConverter.cs @@ -24,39 +24,17 @@ public override MultiPolygon Read(ref Utf8JsonReader reader, Type typeToConvert, } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; IList coordinates = null; - IDictionary additionalProperties = null; - Crs crs = null; - BoundingBox boundingBox = null; - foreach (JsonProperty property in rootElement.EnumerateObject()) + if (rootElement.TryGetProperty(STJMetaDataFields.Polygons, out JsonElement value)) { - if (property.NameEquals(STJMetaDataFields.Polygons)) + coordinates = new List(); + foreach (JsonElement arrayElement in value.EnumerateArray()) { - coordinates = new List(); - foreach (JsonElement arrayElement in property.Value.EnumerateArray()) - { - PolygonCoordinates coordinate = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - coordinates.Add(coordinate); - } + PolygonCoordinates coordinate = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + coordinates.Add(coordinate); } - else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) - { - additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); - Console.WriteLine(additionalProperties.ToString()); - } - else if (property.NameEquals(STJMetaDataFields.Crs)) - { - crs = property.Value.ValueKind == JsonValueKind.Null - ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.GetRawText(), options); - - } - else if (property.NameEquals(STJMetaDataFields.BoundingBox)) - { - boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); - - } - } + + (IDictionary additionalProperties, Crs crs, BoundingBox boundingBox) = SpatialHelper.DeSerializePartialSpatialObject(rootElement, options); return new MultiPolygon(coordinates, new GeometryParams { AdditionalProperties = additionalProperties, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs index abbd186b8e..68f0dfefb5 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PointSTJConverter.cs @@ -24,35 +24,13 @@ public override Point Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; Position pos = null; - IDictionary additionalProperties = null; - Crs crs = null; - BoundingBox boundingBox = null; - - foreach (JsonProperty property in rootElement.EnumerateObject()) + if (rootElement.TryGetProperty(STJMetaDataFields.Position, out JsonElement value)) { - if (property.NameEquals(STJMetaDataFields.Position)) - { - pos = JsonSerializer.Deserialize(property.Value.GetRawText(), options); - } - else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) - { - additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); - - } - else if (property.NameEquals(STJMetaDataFields.Crs)) - { - crs = property.Value.ValueKind == JsonValueKind.Null - ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.GetRawText(), options); - - } - else if (property.NameEquals(STJMetaDataFields.BoundingBox)) - { - boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); + pos = JsonSerializer.Deserialize(value.GetRawText(), options); + } - } + (IDictionary additionalProperties, Crs crs, BoundingBox boundingBox) = SpatialHelper.DeSerializePartialSpatialObject(rootElement, options); - } return new Point(pos, new GeometryParams { AdditionalProperties = additionalProperties, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs index 89ad61627c..58c958cd99 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/PolygonSTJConverter.cs @@ -24,38 +24,18 @@ public override Polygon Read(ref Utf8JsonReader reader, Type typeToConvert, Json } JsonElement rootElement = JsonDocument.ParseValue(ref reader).RootElement; IList linearRings = null; - IDictionary additionalProperties = null; - Crs crs = null; - BoundingBox boundingBox = null; - foreach (JsonProperty property in rootElement.EnumerateObject()) - { - if (property.NameEquals(STJMetaDataFields.Rings)) - { - linearRings = new List(); - foreach (JsonElement arrayElement in property.Value.EnumerateArray()) - { - LinearRing linearRing = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); - linearRings.Add(linearRing); - } - } - else if (property.NameEquals(STJMetaDataFields.AdditionalProperties)) - { - additionalProperties = JsonSerializer.Deserialize>(property.Value.GetRawText(), options); - } - else if (property.NameEquals(STJMetaDataFields.Crs)) - { - crs = property.Value.ValueKind == JsonValueKind.Null - ? Crs.Unspecified - : JsonSerializer.Deserialize(property.Value.GetRawText(), options); - } - else if (property.NameEquals(STJMetaDataFields.BoundingBox)) + if (rootElement.TryGetProperty(STJMetaDataFields.Rings, out JsonElement value)) + { + linearRings = new List(); + foreach (JsonElement arrayElement in value.EnumerateArray()) { - boundingBox = JsonSerializer.Deserialize(property.Value.GetRawText(), options); - + LinearRing linearRing = JsonSerializer.Deserialize(arrayElement.GetRawText(), options); + linearRings.Add(linearRing); } - } + + (IDictionary additionalProperties, Crs crs, BoundingBox boundingBox) = SpatialHelper.DeSerializePartialSpatialObject(rootElement, options); return new Polygon(linearRings, new GeometryParams { AdditionalProperties = additionalProperties, diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs index 8e432c35c3..cd7db9db03 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/STJMetaDataFields.cs @@ -8,13 +8,8 @@ namespace Microsoft.Azure.Cosmos.Spatial.Converters.STJConverters using System.Collections.Generic; using System.Text; - internal class STJMetaDataFields + internal static class STJMetaDataFields { - private STJMetaDataFields() - { - throw new InvalidOperationException(" cannot instantitate utility class. use it as static reference"); - } - public const string Position = "position"; public const string AdditionalProperties = "additionalProperties"; public const string Crs = "crs"; diff --git a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs index e72e01ef15..5d216a7c8e 100644 --- a/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs +++ b/Microsoft.Azure.Cosmos/src/Spatial/Converters/STJConverters/SpatialHelper.cs @@ -28,6 +28,32 @@ public static void SerializePartialSpatialObject(Crs crs, int spatialType, Bound } + public static (IDictionary, Crs, BoundingBox) DeSerializePartialSpatialObject(JsonElement rootElement, JsonSerializerOptions options) + { + IDictionary additionalProperties = null; + Crs crs = null; + BoundingBox boundingBox = null; + + if (rootElement.TryGetProperty(STJMetaDataFields.AdditionalProperties, out JsonElement value)) + { + additionalProperties = JsonSerializer.Deserialize>(value.GetRawText(), options); + } + if (rootElement.TryGetProperty(STJMetaDataFields.Crs, out JsonElement crsValue)) + { + crs = crsValue.ValueKind == JsonValueKind.Null + ? Crs.Unspecified + : JsonSerializer.Deserialize(crsValue.GetRawText(), options); + + } + if (rootElement.TryGetProperty(STJMetaDataFields.BoundingBox, out JsonElement boxValue)) + { + boundingBox = JsonSerializer.Deserialize(boxValue.GetRawText(), options); + } + + return (additionalProperties, crs, boundingBox); + + } + } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs index 801db01f68..b96efda177 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ClientTests.cs @@ -31,7 +31,6 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests using Newtonsoft.Json.Linq; using Microsoft.Azure.Cosmos.Spatial; using System.Text.Json; - //using System.Drawing; [TestClass] public class ClientTests @@ -967,8 +966,8 @@ public async Task ValidateSpatialPointSTJSerialization() new GeometryParams { AdditionalProperties = new Dictionary { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" + ["one"] = "a large one", + ["two"] = "a new two" }, Crs = Crs.Linked("http://foo.com", "link") }); @@ -1007,8 +1006,8 @@ public async Task ValidateSpatialPointNewtonSoftSerialization() { AdditionalProperties = new Dictionary { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" + ["one"] = "a large one", + ["two"] = "a new two" }, Crs = Crs.Linked("http://foo.com", "link") }); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs index 957d00d37b..f40ed1f193 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/PointTest.cs @@ -51,7 +51,6 @@ public void TestPointSerialization() string json1 = JsonConvert.SerializeObject(point); var geom1 = JsonConvert.DeserializeObject(json1); Assert.AreEqual(geom1, geom); - } /// diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs index d4cf2156f6..2e9a2dedb6 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Spatial/STJSpatialTest.cs @@ -141,23 +141,23 @@ public void TestGeometricCollectionSerialization() }, new object[] { new Point( - new Position(20, 30), + new Position(20.4, 30.1), new GeometryParams { AdditionalProperties = new Dictionary { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" + ["one"] = 1, + ["two"] = 2 }, }) }, new object[] { new Point( - new Position(20, 30), + new Position(20.2, 30.9), new GeometryParams { AdditionalProperties = new Dictionary { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" + ["one"] = 1.2, + ["two"] = 3.4 }, BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), Crs = new UnspecifiedCrs() @@ -165,12 +165,12 @@ public void TestGeometricCollectionSerialization() }, new object[] { new Point( - new Position(20, 30), + new Position(20.5, 30.4), new GeometryParams { AdditionalProperties = new Dictionary { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" + ["one"] = "a large one", + ["two"] = "a new two" }, BoundingBox = new BoundingBox(new Position(0, 0), new Position(40, 40)), }) @@ -181,8 +181,8 @@ public void TestGeometricCollectionSerialization() new GeometryParams { AdditionalProperties = new Dictionary { - ["battle"] = "a large abttle", - ["cruise"] = "a new cruise" + ["one"] = "a large one", + ["two"] = "a new two" }, Crs = new UnspecifiedCrs() })