Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Homogenize exceptions in GeoJSON #132

Merged
merged 3 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ private static IList<object> InternalReadJsonArray(JsonReader reader, JsonSerial
case JsonToken.EndConstructor:
case JsonToken.EndObject:
case JsonToken.PropertyName:
throw new JsonException("Expected token ']' or '[' token, or a value");
throw new JsonReaderException("Expected token ']' or '[' token, or a value");

default:
// add value to list
Expand Down Expand Up @@ -142,7 +142,7 @@ private static object InternalReadJson(JsonReader reader, JsonSerializer seriali

if (reader.TokenType != JsonToken.StartObject)
{
throw new ArgumentException("Expected token '{' not found.");
throw new JsonReaderException("Expected token '{' not found");
}

// Advance reader
Expand All @@ -165,7 +165,7 @@ private static object InternalReadJson(JsonReader reader, JsonSerializer seriali
attributeValue = InternalReadJson(reader, serializer, true);
if (reader.TokenType != JsonToken.EndObject)
{
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");
}

// read EndObject token
Expand Down Expand Up @@ -208,7 +208,7 @@ private static object InternalReadJson(JsonReader reader, JsonSerializer seriali
// TODO: refactor to remove check when reading TopoJSON
if (reader.TokenType != JsonToken.EndObject)
{
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");
}

return attributesTable;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
reader.Read();
if (reader.TokenType != JsonToken.StartArray)
{
throw new ArgumentException("Expected token '[' not found.");
throw new JsonReaderException("Expected token '[' not found");
}

// move to first feature
Expand All @@ -103,7 +103,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
reader.Read();
if (reader.TokenType != JsonToken.String && (string)reader.Value != "FeatureCollection")
{
throw new ArgumentException("Expected value 'FeatureCollection' not found.");
throw new JsonReaderException("Expected value 'FeatureCollection' not found");
}

read = reader.Read();
Expand All @@ -114,13 +114,13 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
/*
read = reader.Read();
if (reader.TokenType != JsonToken.StartArray)
throw new ArgumentException("Expected token '{' not found.");
throw new JsonReaderException("Expected token '{' not found");

var env = serializer.Deserialize<double[]>(reader);
fc.BoundingBox = new Envelope(env[0], env[2], env[1], env[3]);

if (reader.TokenType != JsonToken.EndArray)
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");

read = reader.Read();
*/
Expand All @@ -146,7 +146,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist

if (read && reader.TokenType != JsonToken.EndObject)
{
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");
}

return fc;
Expand Down
14 changes: 7 additions & 7 deletions src/NetTopologySuite.IO.GeoJSON/Converters/FeatureConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
{
if (reader.TokenType != JsonToken.StartObject)
{
throw new JsonReaderException("Expected Start object '{' Token");
throw new JsonReaderException("Expected token '{' not found");
}

bool read = reader.Read();
Expand All @@ -101,7 +101,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
reader.Read();
if ((string)reader.Value != "Feature")
{
throw new ArgumentException("Expected value 'Feature' not found.");
throw new JsonReaderException("Expected value 'Feature' not found");
}

read = reader.Read();
Expand Down Expand Up @@ -144,13 +144,13 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist

if (reader.TokenType != JsonToken.StartObject)
{
throw new ArgumentException("Expected token '{' not found.");
throw new JsonReaderException("Expected token '{' not found");
}

feature.Geometry = serializer.Deserialize<Geometry>(reader);
if (reader.TokenType != JsonToken.EndObject)
{
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");
}

read = reader.Read();
Expand All @@ -163,7 +163,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
// #120: ensure "properties" isn't "null"
if (reader.TokenType != JsonToken.StartObject)
{
throw new ArgumentException("Expected token '{' not found.");
throw new JsonReaderException("Expected token '{' not found");
}

var attributes = serializer.Deserialize<AttributesTable>(reader);
Expand All @@ -185,7 +185,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist

if (reader.TokenType != JsonToken.EndObject)
{
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");
}
}
read = reader.Read();
Expand All @@ -207,7 +207,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist

if (read && reader.TokenType != JsonToken.EndObject)
{
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");
}

return feature;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
{
if (reader.TokenType != JsonToken.StartArray)
{
throw new Exception();
throw new JsonReaderException("Expected token '[' not found");
}

reader.Read();
Expand Down Expand Up @@ -122,7 +122,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
break;

case GeoJsonObjectType.GeometryCollection:
throw new NotSupportedException();
throw new JsonReaderException("GeometryCollection is currently not supported.");
}

reader.Read();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ private Geometry ParseGeometry(JsonReader reader, JsonSerializer serializer)

if (reader.TokenType != JsonToken.StartObject)
{
throw new JsonReaderException("Expected Start object '{' Token");
throw new JsonReaderException("Expected token '{' not found");
}

// advance
Expand All @@ -407,8 +407,9 @@ private Geometry ParseGeometry(JsonReader reader, JsonSerializer serializer)
if (geometryType == null)
{
reader.ReadOrThrow();
geometryType = (GeoJsonObjectType)Enum.Parse(typeof(GeoJsonObjectType),
(string)reader.Value, true);
geometryType = Enum.TryParse((string)reader.Value, true, out GeoJsonObjectType parsedGeometryType)
? parsedGeometryType
: throw new JsonReaderException($"Unknown geometry type '{(string)reader.Value}'");
reader.ReadOrThrow();
}

Expand Down Expand Up @@ -453,7 +454,7 @@ private Geometry ParseGeometry(JsonReader reader, JsonSerializer serializer)

if (reader.TokenType != JsonToken.EndObject)
{
throw new ArgumentException("Expected token '}' not found.");
throw new JsonReaderException("Expected token '}' not found");
}

bool CoordsIsNullOrEmpty() => coords is null || coords.Count == 0;
Expand Down
35 changes: 31 additions & 4 deletions src/NetTopologySuite.IO.GeoJSON/GeoJsonReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class GeoJsonReader
private readonly GeometryFactory _factory;
private readonly JsonSerializerSettings _serializerSettings;
private readonly int _dimension;
private readonly RingOrientationOption _ringOrientationOption;

/// <summary>
/// Creates an instance of this class
Expand All @@ -30,7 +31,7 @@ public GeoJsonReader()
/// <param name="factory">The factory to use when creating geometries</param>
/// <param name="serializerSettings">The serializer setting</param>
public GeoJsonReader(GeometryFactory factory, JsonSerializerSettings serializerSettings)
: this(factory, serializerSettings, 2)
: this(factory, serializerSettings, GeoJsonSerializer.Dimension)
{
}

Expand All @@ -41,11 +42,26 @@ public GeoJsonReader(GeometryFactory factory, JsonSerializerSettings serializerS
/// <param name="factory">The factory to use when creating geometries</param>
/// <param name="serializerSettings">The serializer setting</param>
/// <param name="dimension">The number of dimensions to handle. Must be 2 or 3.</param>
public GeoJsonReader(GeometryFactory factory, JsonSerializerSettings serializerSettings, int dimension)
public GeoJsonReader(GeometryFactory factory, JsonSerializerSettings serializerSettings, int dimension) :
this(factory, serializerSettings, dimension, GeoJsonSerializer.RingOrientationOption)
{
}

/// <summary>
/// Creates an instance of this class using the provided <see cref="GeometryFactory"/> and
/// <see cref="JsonSerializerSettings"/>.
/// </summary>
/// <param name="factory">The factory to use when creating geometries</param>
/// <param name="serializerSettings">The serializer setting</param>
/// <param name="dimension">The number of dimensions to handle. Must be 2 or 3.</param>
/// <param name="ringOrientationOption"></param>
public GeoJsonReader(GeometryFactory factory, JsonSerializerSettings serializerSettings,
int dimension, RingOrientationOption ringOrientationOption)
{
_factory = factory;
_serializerSettings = serializerSettings;
_dimension = dimension;
_ringOrientationOption = ringOrientationOption;
}

/// <summary>
Expand Down Expand Up @@ -79,8 +95,19 @@ public TObject Read<TObject>(JsonReader json)
throw new ArgumentNullException(nameof(json));
}

var g = GeoJsonSerializer.Create(_serializerSettings, _factory, _dimension);
return g.Deserialize<TObject>(json);
var g = GeoJsonSerializer.Create(_serializerSettings, _factory, _dimension, _ringOrientationOption);
try
{
return g.Deserialize<TObject>(json);
}
catch (JsonReaderException)
{
throw;
}
catch (Exception ex)
{
throw new JsonReaderException("Failed to correctly read json", ex);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public override IFeature Read(ref Utf8JsonReader reader, Type objectType, JsonSe
{
case "type":
if (reader.GetString() != "Feature")
throw new ArgumentException("Expected value 'Feature' not found.");
throw new JsonException("Expected value 'Feature' not found.");
reader.Read();
break;

Expand Down
68 changes: 68 additions & 0 deletions test/NetTopologySuite.IO.GeoJSON.Test/GeoJsonReaderTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using NetTopologySuite.Features;
using NetTopologySuite.Geometries;
using Newtonsoft.Json;
using NUnit.Framework;
using System.IO;

namespace NetTopologySuite.IO.GeoJSON.Test
{
Expand Down Expand Up @@ -309,5 +311,71 @@ public void GeoJsonReaderReadGeometryCollectionTest()
Assert.AreEqual(102, lineString.Coordinates[1].X);
Assert.AreEqual(1, lineString.Coordinates[1].Y);
}

[Test]
public void TestMalformedPoint()
{
var rdr = new GeoJsonReader();

// Point
Assert.That(() => rdr.Read<Point>("\"type\": \"Point\", \"coordinates\": [99.0, 89.0]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Point>("{\"type\": \"Point\", \"coordinates\": [99.0, 89.0]{"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Point>("{\"type\": \"Point\", \"coordinates\": [99.0, 89.0]"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Point>("{\"type\": \"Pooint\", \"coordinates\": [99.0, 89.0]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Point>("{\"type\": \"Point\", \"coordinates\": [99.0, B]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Point>("{\"type\": \"Point\", \"coordinates\": 99.0, 89.0]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Point>("{\"type\": \"Point\", \"coordinates\": [99.0, 89.0}"),
Throws.InstanceOf<JsonReaderException>());
}

[Test]
public void TestMalformedLineString()
{
var rdr = new GeoJsonReader();

// LineString
Assert.That(() => rdr.Read<LineString>("\"type\": \"LineString\", \"coordinates\": [[99.0, 89.0], 100.0, 89.0]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<LineString>("{\"type\": \"LineString\", \"coordinates\": [[99.0, 89.0], [100.0, 89.0]]{"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<LineString>("{\"type\": \"LineString\", \"coordinates\": [[99.0, 89.0], [100.0, 89.0]]"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<LineString>("{\"type\": \"LineSting\", \"coordinates\": [[99.0, 89.0], [100.0, 89.0]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<LineString>("{\"type\": \"LineString\", \"coordinates\": [[99.0, B], [100.0, 89.0]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<LineString>("{\"type\": \"LineString\", \"coordinates\": [99.0, 89.0], [100.0, 89.0]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<LineString>("{\"type\": \"LineString\", \"coordinates\": [[99.0, 89.0], [100.0, 89.0]}"),
Throws.InstanceOf<JsonReaderException>());
}

[Test]
public void TestMalformedPolygon()
{
var rdr = new GeoJsonReader();

// Polygon
Assert.That(() => rdr.Read<Polygon>("\"type\": \"Polygon\", \"coordinates\": [[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Polygon>("\"type\": \"Polygon\", \"coordinates\": [[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]]{"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Polygon>("\"type\": \"Polygon\", \"coordinates\": [[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]]"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Polygon>("\"type\": \"Poygon\", \"coordinates\": [[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Polygon>("\"type\": \"Polygon\", \"coordinates\": [[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, A.0], [100.0, 0.0] ]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Polygon>("\"type\": \"Polygon\", \"coordinates\": [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]]}"),
Throws.InstanceOf<JsonReaderException>());
Assert.That(() => rdr.Read<Polygon>("\"type\": \"Polygon\", \"coordinates\": [[ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], [100.0, 1.0], [100.0, 0.0] ]}"),
Throws.InstanceOf<JsonReaderException>());
}
}
}