GeoJson error when deserializing List<Coordinate[]>
I am running into an error when deserializing an Enumerable<Enumerable<Coordinate>>, specifically a property of type List<Coordinate[]> (but the same error happens if I use a Coordinate[][] ).
I get the following error:
Unexpected token when deserializing object: EndArray. Path 'Plan.Floors.$values[0].Polygons[0][0]', line 440, position 15.
I am adding a new NetTopologySuite.IO.Converters.CoordinateConverter() to the JsonSerializerSettings and I can see it gets called during deserialization by debugging.
The object is serialized using the same JsonSerializerSettings, which seems to work fine.
The serialized property looks like this:
"Polygons": [
[
[
203.79584390716113,
72.54154079959201
], // <- this is line 440
[
203.79584390716113,
-100.95845920040797
],
[
-83.70415609283884,
-100.95845920040794
],
[
-83.70415609283884,
72.54154079959201
]
]
],
I am not very familiar with the inner workings of the deserializer, but I have a feeling it reads one line too much before deserializing and it lands on the first float when it's expecting a StartArray token.
Is this a bug in the deserializer or am I doing something wrong?
The JSON looks it's not a valid geojson: please check with a geojson validator that you can find online
Thank you. I exported just Coordinates using the CoordinateConverter, so perhaps that's not how it's supposed to be used? I see somewhere in the code that CoordinateConverter is expecting a "coordinates" : [] object when deserializing json, but it never writes it when serializing.
Do you serialized a polygon using just the coordinate converter? Actually, it's hard to understand to me what is the problem are you facing, or the task are you trying to accomplish. Can you post some sample code that helps me to understand what is your goal? Anyway, you can find some sample code in the tests section
It sounds like the issue is just that it was a mistake for this library to have publicly exposed converters for types other than the ones defined in GeoJSON (i.e., we shouldn't provide converters for Coordinate, lists of them, lists of lists of them, etc.), because being able to save and load those types using isn't really something that this library is intended to accomplish.
I am serializing/deserializing a custom class that has the following property
public List<Coordinate[]> Polygons { get; set; } = new List<Coordinate[]>();
with Newtonsoft.JSON and adding a NetTopologySuite.IO.Converters.CoordinateConverter to the Converters in the JsonSerializerSettings.
private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings()
{
ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
ContractResolver = new PrivateIdContractResolver(),
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented,
ObjectCreationHandling = ObjectCreationHandling.Auto,
Converters = new JsonConverter[] {
new ProjectConverter(),
new NetTopologySuite.IO.Converters.CoordinateConverter()
}
};
As you can see, even though the property is called Polygons, I am not actually using the Polygon class from NTS.Geometry. I guess the variable name was misleading, my apologies.
It sounds like the issue is just that it was a mistake for this library to have publicly exposed converters for types other than the ones defined in GeoJSON (i.e., we shouldn't provide converters for
Coordinate, lists of them, lists of lists of them, etc.), because being able to save and load those types using isn't really something that this library is intended to accomplish.
That's what I came to understand as well. I have created my own CoordinateConverter starting from the library now and moved on.
ok based on your code, the json generated looks correct to me
"Polygons": [ <- List of Coordinate[]
[ <- a single Coordinate[] in the list
[ <- A coordinate, serialized as [X,Y] from the CoordinateConverter
203.79584390716113,
72.54154079959201
], // <- this is line 440
[
203.79584390716113,
-100.95845920040797
],
[
-83.70415609283884,
-100.95845920040794
],
[
-83.70415609283884,
72.54154079959201
]
]
],
I can guess that your "polygons" are simple shapes without holes, i.e.: LinearRings (closed polylines)

Polygons can contain holes, so they are serialized with a single LinearRing that represent the external boundary, and optionally one or more LinearRings that represent the hole(s), if any.

ok based on your code, the json generated looks correct to me
It did to me as well. The problem is it can't be deserialized by CoordinateConverter. The problem is that when using the converter by itself, each method that gets called to deserialize an IEnumerable<IEnumerable<Coordinate>> expects the reader to be one-level higher in the tree that it actually is. This breaks the deserialization.
I think when the converter is used by the library the coordinates get encapsulated in a coordinates : [] object outside of the CoordinateConverter. See this code:
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
reader.Read();
Debug.Assert(reader.TokenType == JsonToken.PropertyName);
Debug.Assert((string)reader.Value == "coordinates");
The coordinates property is never created by the CoordinateConverter on serialization.
It did to me as well. The problem is it can't be deserialized by CoordinateConverter.
as @airbreather said earlier, we can just assume that this is not an actual issue, because CoordinateConverter wasn't supposed to be used "standalone". the actual fix shoud be to reduce the visibility of the converters, but this can be considered a breaking change.