Skip to content

Commit

Permalink
Use GeoJsonReaderException in NTS.IO.GeoJSON (#132)
Browse files Browse the repository at this point in the history
closes #92
  • Loading branch information
FObermaier authored Sep 15, 2023
1 parent 0485573 commit 448bf39
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 27 deletions.
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>());
}
}
}

0 comments on commit 448bf39

Please sign in to comment.