Skip to content

Commit 0796e89

Browse files
authored
Add System.Text.Json support for Microsoft.Spatial (Azure#15468)
* Add System.Text.Json support for Microsoft.Spatial * Add tests for NewtonsoftJsonGeographyPointConverter * Export public APIs * Remove case-insensitivity option per feedback * Fix README validation failure * Rename to be ready for all Geography Setting up for Azure#15506 * Use new GeographyConverter Resolves Azure#15431 * Update documentation * Rename converters per arch discussion * Resolve PR feedback * Update public APIs * Resolve PR feedback
1 parent 3d320d9 commit 0796e89

25 files changed

+616
-146
lines changed

eng/.docsettings.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ known_content_issues:
158158
- ['sdk/tables/Azure.Data.Tables/readme.md', '#11492']
159159
- ['sdk/core/Azure.Core.TestFramework/README.md', '#11492']
160160
- ['sdk/core/Microsoft.Azure.Core.NewtonsoftJson/README.md', '#15423']
161+
- ['sdk/core/Microsoft.Azure.Core.Spatial/README.md', '#15423']
161162
- ['sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/README.md', '#15423']
162163

163164
# .net climbs upwards. placing these to prevent assigning readmes to the wrong project

sdk/core/Azure.Core/Azure.Core.All.sln

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Core.Spatia
255255
EndProject
256256
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Core.Spatial.NewtonsoftJson.Tests", "..\Microsoft.Azure.Core.Spatial.NewtonsoftJson\tests\Microsoft.Azure.Core.Spatial.NewtonsoftJson.Tests.csproj", "{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}"
257257
EndProject
258+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Core.Spatial", "..\Microsoft.Azure.Core.Spatial\src\Microsoft.Azure.Core.Spatial.csproj", "{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}"
259+
EndProject
260+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Core.Spatial.Tests", "..\Microsoft.Azure.Core.Spatial\tests\Microsoft.Azure.Core.Spatial.Tests.csproj", "{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}"
261+
EndProject
258262
Global
259263
GlobalSection(SharedMSBuildProjectFiles) = preSolution
260264
..\..\synapse\Azure.Analytics.Synapse.Shared\src\Azure.Analytics.Synapse.Shared.projitems*{14a1ca9b-2387-4b81-84d5-120e4f8ffab8}*SharedItemsImports = 5
@@ -1776,6 +1780,14 @@ Global
17761780
{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
17771781
{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
17781782
{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}.Release|Any CPU.Build.0 = Release|Any CPU
1783+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1784+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
1785+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
1786+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Release|Any CPU.Build.0 = Release|Any CPU
1787+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
1788+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Debug|Any CPU.Build.0 = Debug|Any CPU
1789+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Release|Any CPU.ActiveCfg = Release|Any CPU
1790+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Release|Any CPU.Build.0 = Release|Any CPU
17791791
EndGlobalSection
17801792
GlobalSection(SolutionProperties) = preSolution
17811793
HideSolutionNode = FALSE

sdk/core/Azure.Core/Azure.Core.sln

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Core.Spatia
2121
EndProject
2222
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Core.Spatial.NewtonsoftJson.Tests", "..\Microsoft.Azure.Core.Spatial.NewtonsoftJson\tests\Microsoft.Azure.Core.Spatial.NewtonsoftJson.Tests.csproj", "{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}"
2323
EndProject
24+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Core.Spatial", "..\Microsoft.Azure.Core.Spatial\src\Microsoft.Azure.Core.Spatial.csproj", "{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}"
25+
EndProject
26+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Azure.Core.Spatial.Tests", "..\Microsoft.Azure.Core.Spatial\tests\Microsoft.Azure.Core.Spatial.Tests.csproj", "{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}"
27+
EndProject
2428
Global
2529
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2630
Debug|Any CPU = Debug|Any CPU
@@ -63,6 +67,14 @@ Global
6367
{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
6468
{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
6569
{622772C8-A2CB-4F8B-82EB-2A46BCC21DAE}.Release|Any CPU.Build.0 = Release|Any CPU
70+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
71+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Debug|Any CPU.Build.0 = Debug|Any CPU
72+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Release|Any CPU.ActiveCfg = Release|Any CPU
73+
{25A7E209-D5D2-41F1-AFE9-E860D6294EF5}.Release|Any CPU.Build.0 = Release|Any CPU
74+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
75+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Debug|Any CPU.Build.0 = Debug|Any CPU
76+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Release|Any CPU.ActiveCfg = Release|Any CPU
77+
{36FF59A9-D6C9-4226-A0FE-47C879F3EB94}.Release|Any CPU.Build.0 = Release|Any CPU
6678
EndGlobalSection
6779
GlobalSection(SolutionProperties) = preSolution
6880
HideSolutionNode = FALSE

sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44

55
### Added
66

7-
- Added `NewtonsoftJsonGeographyPointConverter` to serialize `Microsoft.Spatial.GeographyPoint` objects.
7+
- Added `NewtonsoftJsonMicrosoftSpatialGeoJsonConverter` to serialize `Microsoft.Spatial.GeographyPoint` objects.

sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/api/Microsoft.Azure.Core.Spatial.NewtonsoftJson.netstandard2.0.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
namespace Azure.Core.Serialization
22
{
3-
public partial class NewtonsoftJsonGeographyPointConverter : Newtonsoft.Json.JsonConverter
3+
public partial class NewtonsoftJsonMicrosoftSpatialGeoJsonConverter : Newtonsoft.Json.JsonConverter
44
{
5-
public NewtonsoftJsonGeographyPointConverter() { }
5+
public NewtonsoftJsonMicrosoftSpatialGeoJsonConverter() { }
66
public override bool CanConvert(System.Type objectType) { throw null; }
77
public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer) { throw null; }
88
public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer) { }

sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/src/GeoJsonExtensions.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,14 @@ double ReadFloatOrInt()
132132
double longitude = ReadFloatOrInt();
133133
double latitude = ReadFloatOrInt();
134134

135+
// Skip remaining coordinates, e.g. z and m.
136+
while (coordinatesReader.TokenType != JsonToken.EndArray)
137+
{
138+
coordinatesReader.Advance();
139+
}
140+
135141
coordinatesReader.ExpectAndAdvance(JsonToken.EndArray);
142+
136143
return GeographyPoint.Create(latitude, longitude);
137144
}
138145
}

sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/src/Microsoft.Azure.Core.Spatial.NewtonsoftJson.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
<EnableClientSdkAnalyzers>false</EnableClientSdkAnalyzers>
1010
</PropertyGroup>
1111

12-
<Import Project="..\..\Azure.Core\src\Azure.Core.props" />
1312
<ItemGroup>
1413
<PackageReference Include="Microsoft.Spatial" />
1514
<PackageReference Include="Newtonsoft.Json" />

sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/src/NewtonsoftJsonGeographyPointConverter.cs renamed to sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/src/NewtonsoftJsonMicrosoftSpatialGeoJsonConverter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
namespace Azure.Core.Serialization
99
{
1010
/// <summary>
11-
/// Converts between <see cref="GeographyPoint" /> objects and Geo-JSON points.
11+
/// Converts between <c>Microsoft.Spatial</c> objects and Geo-JSON.
1212
/// </summary>
13-
public class NewtonsoftJsonGeographyPointConverter : JsonConverter
13+
public class NewtonsoftJsonMicrosoftSpatialGeoJsonConverter : JsonConverter
1414
{
1515
/// <inheritdoc/>
1616
public override bool CanConvert(Type objectType) =>
17+
// BUGBUG #15506: Check for all Geography derivatives.
1718
typeof(GeographyPoint).IsAssignableFrom(objectType);
1819

1920
/// <inheritdoc/>

sdk/core/Microsoft.Azure.Core.Spatial.NewtonsoftJson/tests/NewtonsoftJsonGeographyPointConverterTests.cs

Lines changed: 0 additions & 49 deletions
This file was deleted.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System.Collections.Generic;
5+
using Azure.Core.Serialization;
6+
using Microsoft.Spatial;
7+
using Newtonsoft.Json;
8+
using NUnit.Framework;
9+
10+
namespace Microsoft.Azure.Core.Spatial.NewtonsoftJson.Tests
11+
{
12+
public class NewtonsoftJsonMicrosoftSpatialGeoJsonConverterTests
13+
{
14+
[Test]
15+
public void CanConvert()
16+
{
17+
NewtonsoftJsonMicrosoftSpatialGeoJsonConverter converter = new NewtonsoftJsonMicrosoftSpatialGeoJsonConverter();
18+
Assert.IsTrue(converter.CanConvert(typeof(GeographyPoint)));
19+
}
20+
21+
[Test]
22+
public void ReadJson()
23+
{
24+
JsonSerializerSettings settings = new JsonSerializerSettings
25+
{
26+
Converters =
27+
{
28+
new NewtonsoftJsonMicrosoftSpatialGeoJsonConverter(),
29+
},
30+
};
31+
32+
GeographyPoint point = JsonConvert.DeserializeObject<GeographyPoint>(@"{""type"":""Point"",""coordinates"":[-121.726906,46.879967]}", settings);
33+
34+
Assert.AreEqual(point.Latitude, 46.879967);
35+
Assert.AreEqual(point.Longitude, -121.726906);
36+
}
37+
38+
[Test]
39+
public void ReadJsonMore()
40+
{
41+
JsonSerializerSettings settings = new JsonSerializerSettings
42+
{
43+
Converters =
44+
{
45+
new NewtonsoftJsonMicrosoftSpatialGeoJsonConverter(),
46+
},
47+
};
48+
49+
GeographyPoint point = JsonConvert.DeserializeObject<GeographyPoint>(@"{""type"":""Point"",""coordinates"":[-121.726906,46.879967,2541.118],""crs"":{""type"":""name"",""properties"":{""name"":""EPSG:4326""}}}", settings);
50+
51+
Assert.AreEqual(point.Latitude, 46.879967);
52+
Assert.AreEqual(point.Longitude, -121.726906);
53+
54+
// Not currently supported.
55+
Assert.IsNull(point.Z);
56+
}
57+
58+
[Test]
59+
public void ReadIntegers()
60+
{
61+
JsonSerializerSettings settings = new JsonSerializerSettings
62+
{
63+
Converters =
64+
{
65+
new NewtonsoftJsonMicrosoftSpatialGeoJsonConverter(),
66+
},
67+
};
68+
69+
GeographyPoint point = JsonConvert.DeserializeObject<GeographyPoint>(@"{""type"":""Point"",""coordinates"":[-121,46]}", settings);
70+
71+
Assert.AreEqual(46.0, point.Latitude);
72+
Assert.AreEqual(-121.0, point.Longitude);
73+
74+
// Not currently supported.
75+
Assert.IsNull(point.Z);
76+
}
77+
78+
[TestCaseSource(nameof(ReadBadJsonData))]
79+
public void ReadBadJson(string json, string expectedExceptionMessage)
80+
{
81+
JsonSerializerSettings settings = new JsonSerializerSettings
82+
{
83+
Converters =
84+
{
85+
new NewtonsoftJsonMicrosoftSpatialGeoJsonConverter(),
86+
},
87+
};
88+
89+
JsonSerializationException expectedException = Assert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<GeographyPoint>(json, settings));
90+
Assert.AreEqual(expectedExceptionMessage, expectedException.Message);
91+
}
92+
93+
private static IEnumerable<TestCaseData> ReadBadJsonData => new[]
94+
{
95+
new TestCaseData(@"[]", $"Deserialization failed. Expected token: '{nameof(JsonToken.StartObject)}'"),
96+
new TestCaseData(@"{}", $"Deserialization failed. Could not find required 'type' property."),
97+
new TestCaseData(@"{""type"":""point""}", $"Deserialization failed. Expected value(s): 'Point'. Actual: 'point'"),
98+
new TestCaseData(@"{""type"":""Polygon""}", $"Deserialization failed. Expected value(s): 'Point'. Actual: 'Polygon'"),
99+
new TestCaseData(@"{""Type"":""Point""}", $"Deserialization failed. Expected value(s): 'type, coordinates, crs'. Actual: 'Type'"),
100+
new TestCaseData(@"{""type"":""Point"",""Coordinates"":[-121.726906,46.879967]}", $"Deserialization failed. Expected value(s): 'type, coordinates, crs'. Actual: 'Coordinates'"),
101+
new TestCaseData(@"{""type"":""Point"",""coordinates"":-121.726906}", $"Deserialization failed. Expected token: '{nameof(JsonToken.StartArray)}'"),
102+
new TestCaseData(@"{""type"":""Point"",""coordinates"":[]}", $"Deserialization failed. Expected token: '{nameof(JsonToken.Float)}'"),
103+
new TestCaseData(@"{""type"":""Point"",""coordinates"":[""foo""]}", $"Deserialization failed. Expected token: '{nameof(JsonToken.Float)}'"),
104+
new TestCaseData(@"{""type"":""Point"",""coordinates"":[-121.726906]}", $"Deserialization failed. Expected token: '{nameof(JsonToken.Float)}'"),
105+
};
106+
107+
[Test]
108+
public void WriteJson()
109+
{
110+
JsonSerializerSettings settings = new JsonSerializerSettings
111+
{
112+
Converters =
113+
{
114+
new NewtonsoftJsonMicrosoftSpatialGeoJsonConverter(),
115+
},
116+
};
117+
118+
GeographyPoint point = GeographyPoint.Create(46.879967, -121.726906);
119+
string json = JsonConvert.SerializeObject(point, settings);
120+
121+
// Use regex comparison since double precision can be slight off.
122+
StringAssert.IsMatch(@"\{""type\"":""Point"",""coordinates"":\[-121\.72690\d+,46\.87996\d+\]\}", json);
123+
}
124+
}
125+
}

0 commit comments

Comments
 (0)