forked from Azure/azure-sdk-for-net
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Json.NET converters for Microsoft.Spatial
Resolves Azure#13165
- Loading branch information
Showing
11 changed files
with
672 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Release History | ||
|
||
## 1.0.0-preview.1 (Unreleased) |
7 changes: 7 additions & 0 deletions
7
sdk/search/Microsoft.Spatial.NewtonsoftJson/Directory.Build.props
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<PropertyGroup> | ||
<IsClientLibrary>true</IsClientLibrary> | ||
</PropertyGroup> | ||
|
||
<Import Project="..\Directory.Build.props" /> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# Newtonsoft.Json implementation for Microsoft.Spatial library for .NET | ||
|
||
Microsoft.Spatial contains classes and methods that facilitate geography and geometry spatial operations. | ||
This library contains implementations dependent on Newtonsoft.Json, aka JSON.NET, for use with Microsoft.Spatial. | ||
|
||
## Getting started | ||
|
||
TODO | ||
|
||
### Install the package | ||
|
||
TODO | ||
|
||
### Prerequisites | ||
|
||
TODO | ||
|
||
### Authenticate the client | ||
|
||
TODO | ||
|
||
## Key concepts | ||
|
||
TODO | ||
|
||
## Examples | ||
|
||
TODO | ||
|
||
## Troubleshooting | ||
|
||
TODO | ||
|
||
## Next steps | ||
|
||
TODO | ||
|
||
## Contributing | ||
|
||
This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit <https://cla.microsoft.com>. | ||
|
||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA. | ||
|
||
This project has adopted the [Microsoft Open Source Code of Conduct][code_of_conduct]. For more information see the [Code of Conduct FAQ][code_of_conduct_faq] or contact opencode@microsoft.com with any additional questions or comments. | ||
|
||
![Impressions](https://azure-sdk-impressions.azurewebsites.net/api/impressions/azure-sdk-for-net%2Fsdk%2Fcore%2FMicrosoft.Azure.Core.NewtonsoftJson%2FREADME.png) | ||
|
||
[code_of_conduct]: https://opensource.microsoft.com/codeofconduct | ||
[code_of_conduct_faq]: https://opensource.microsoft.com/codeofconduct/faq/ |
185 changes: 185 additions & 0 deletions
185
sdk/search/Microsoft.Spatial.NewtonsoftJson/src/GeoJsonExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System.Collections.Generic; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Linq; | ||
|
||
namespace Microsoft.Spatial.Serialization | ||
{ | ||
/// <summary> | ||
/// Defines extension methods for various JSON.NET types that make it easier to recognize and read Geo-JSON. | ||
/// </summary> | ||
internal static class GeoJsonExtensions | ||
{ | ||
private const string Coordinates = "coordinates"; | ||
private const string Crs = "crs"; | ||
private const string Name = "name"; | ||
private const string Point = "Point"; | ||
private const string Properties = "properties"; | ||
private const string Type = "type"; | ||
private const string WorldGeodeticSystem1984 = "EPSG:4326"; // See https://epsg.io/4326 | ||
|
||
private static readonly IEnumerable<string> CrsOnly = new[] { Crs }; | ||
private static readonly IEnumerable<string> NameOnly = new[] { Name }; | ||
private static readonly IEnumerable<string> TypeAndCoordinates = new[] { Type, Coordinates }; | ||
private static readonly IEnumerable<string> TypeAndProperties = new[] { Type, Properties }; | ||
|
||
/// <summary> | ||
/// Determines whether the given <see cref="JObject" /> is a valid Geo-JSON point. | ||
/// </summary> | ||
/// <param name="obj">The JSON object to test.</param> | ||
/// <returns><c>true</c> if the JSON object is not null and is a valid Geo-JSON point, <c>false</c> otherwise.</returns> | ||
public static bool IsGeoJsonPoint(this JObject obj) => | ||
obj?.IsValid( | ||
requiredProperties: TypeAndCoordinates, | ||
isPropertyValid: property => | ||
{ | ||
switch (property.Name) | ||
{ | ||
case Type: | ||
return property.Value.IsString(Point); | ||
case Coordinates: | ||
return AreCoordinates(property.Value); | ||
case Crs: | ||
return property.Value is JObject possibleCrs && IsCrs(possibleCrs); | ||
default: | ||
return false; | ||
} | ||
}) ?? false; | ||
|
||
/// <summary> | ||
/// Reads a Geo-JSON point into a <see cref="GeographyPoint" /> instance, or throws | ||
/// <see cref="JsonSerializationException" /> if the reader is not positioned on the | ||
/// beginning of a valid Geo-JSON point. | ||
/// </summary> | ||
/// <param name="reader">The JSON reader from which to read a Geo-JSON point.</param> | ||
/// <returns>A <see cref="GeographyPoint" /> instance.</returns> | ||
public static GeographyPoint ReadGeoJsonPoint(this JsonReader reader) | ||
{ | ||
// Check for null first. | ||
if (reader.TokenType == JsonToken.Null) | ||
{ | ||
return null; | ||
} | ||
|
||
GeographyPoint result = null; | ||
|
||
reader.ReadObject( | ||
requiredProperties: TypeAndCoordinates, | ||
optionalProperties: CrsOnly, | ||
readProperty: (r, propertyName) => | ||
{ | ||
switch (propertyName) | ||
{ | ||
case Type: | ||
r.ExpectAndAdvance(JsonToken.String, Point); | ||
break; | ||
case Coordinates: | ||
result = ReadCoordinates(r); | ||
break; | ||
case Crs: | ||
ReadCrs(r); | ||
break; | ||
} | ||
}); | ||
|
||
return result; | ||
} | ||
|
||
/// <summary> | ||
/// Writes a <see cref="GeographyPoint" /> instance as Geo-JSON format. | ||
/// </summary> | ||
/// <param name="writer">The JSON writer to which to write the Geo-JSON point.</param> | ||
/// <param name="point">The <see cref="GeographyPoint" /> instance to write.</param> | ||
public static void WriteGeoJsonPoint(this JsonWriter writer, GeographyPoint point) | ||
{ | ||
writer.WriteStartObject(); | ||
writer.WritePropertyName(Type); | ||
writer.WriteValue(Point); | ||
writer.WritePropertyName(Coordinates); | ||
writer.WriteStartArray(); | ||
writer.WriteValue(point.Longitude); | ||
writer.WriteValue(point.Latitude); | ||
writer.WriteEndArray(); | ||
writer.WriteEndObject(); | ||
} | ||
|
||
private static bool IsCrsProperties(JObject possibleProperties) => | ||
possibleProperties.IsValid( | ||
requiredProperties: NameOnly, | ||
isPropertyValid: property => property.Name == Name && property.Value.IsString(WorldGeodeticSystem1984)); | ||
|
||
private static void ReadCrsProperties(JsonReader propertiesReader) => | ||
propertiesReader.ReadObjectAndAdvance( | ||
requiredProperties: NameOnly, | ||
readProperty: (r, _) => r.ExpectAndAdvance(JsonToken.String, WorldGeodeticSystem1984)); | ||
|
||
private static bool IsCrs(JObject possibleCrs) => | ||
possibleCrs.IsValid( | ||
requiredProperties: TypeAndProperties, | ||
isPropertyValid: property => | ||
{ | ||
switch (property.Name) | ||
{ | ||
case Type: | ||
return property.Value.IsString(Name); | ||
case Properties: | ||
return property.Value is JObject possibleProperties && IsCrsProperties(possibleProperties); | ||
default: | ||
return false; | ||
} | ||
}); | ||
|
||
private static void ReadCrs(JsonReader crsReader) => | ||
crsReader.ReadObjectAndAdvance( | ||
requiredProperties: TypeAndProperties, | ||
readProperty: (r, propertyName) => | ||
{ | ||
switch (propertyName) | ||
{ | ||
case Type: | ||
r.ExpectAndAdvance(JsonToken.String, Name); | ||
break; | ||
case Properties: | ||
ReadCrsProperties(r); | ||
break; | ||
} | ||
}); | ||
|
||
private static bool AreCoordinates(JToken possibleCoordinates) => | ||
possibleCoordinates is JArray array && array.Count == 2 && array[0].IsNumber() && array[1].IsNumber(); | ||
|
||
private static GeographyPoint ReadCoordinates(JsonReader coordinatesReader) | ||
{ | ||
coordinatesReader.ExpectAndAdvance(JsonToken.StartArray); | ||
|
||
double ReadFloatOrInt() | ||
{ | ||
switch (coordinatesReader.TokenType) | ||
{ | ||
case JsonToken.Integer: | ||
return coordinatesReader.ExpectAndAdvance<long>(JsonToken.Integer); | ||
|
||
// Treat all other cases as Float and let ExpectAndAdvance() handle any errors. | ||
default: | ||
return coordinatesReader.ExpectAndAdvance<double>(JsonToken.Float); | ||
} | ||
} | ||
|
||
double longitude = ReadFloatOrInt(); | ||
double latitude = ReadFloatOrInt(); | ||
|
||
coordinatesReader.ExpectAndAdvance(JsonToken.EndArray); | ||
return GeographyPoint.Create(latitude, longitude); | ||
} | ||
} | ||
} |
26 changes: 26 additions & 0 deletions
26
sdk/search/Microsoft.Spatial.NewtonsoftJson/src/GeographyPointConverter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// Copyright (c) Microsoft Corporation. All rights reserved. | ||
// Licensed under the MIT License. | ||
|
||
using System; | ||
using Newtonsoft.Json; | ||
|
||
namespace Microsoft.Spatial.Serialization | ||
{ | ||
/// <summary> | ||
/// Converts between <see cref="GeographyPoint" /> objects and Geo-JSON points. | ||
/// </summary> | ||
public class GeographyPointConverter : JsonConverter | ||
{ | ||
/// <inheritdoc/> | ||
public override bool CanConvert(Type objectType) => | ||
typeof(GeographyPoint).IsAssignableFrom(objectType); | ||
|
||
/// <inheritdoc/> | ||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => | ||
reader.ReadGeoJsonPoint(); | ||
|
||
/// <inheritdoc/> | ||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => | ||
writer.WriteGeoJsonPoint((GeographyPoint)value); | ||
} | ||
} |
Oops, something went wrong.