Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON.NET - Conditional Type Deserialization

Tags:

I'm consuming some ARCGis web services, and they have some unfortunate JSON design. for example, they might give something like this:

{ geometryType: "esriGeometryPolygon" geometry: { -rings: [ -[.blah..... }} 

Now, depending on the geometryType value passed in, the geometry object may be one of several different object types. in the case above, the geometry node is of type Polygon.

so, question is; in JSON.NET is there any way to notate this conditional typing? if not (which i doubt there is), is there a way to build a provider for deserializing that geometry node, based on the object info above? if not, are there any recommended ways for solving this?

edit: i looked pretty extensively into building a custom converter, but the problem with the converter is that they have this abstract method:

public override T Create (Type objectType) 

however, i have no way of knowing what type to create here, i need to know what kind of object was specified in the JSON above.

thanks!

like image 223
bryan costanich Avatar asked Oct 19 '11 05:10

bryan costanich


People also ask

What is JSON serialization deserialization?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object).

How do I deserialize a JSON file?

A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.

What is JSON serialization and deserialization in C#?

Serialization is the process of converting . NET objects such as strings into a JSON format and deserialization is the process of converting JSON data into . NET objects.

How does Newtonsoft JSON deserialize work?

Newtonsoft. Json uses reflection to get constructor parameters and then tries to find closest match by name of these constructor parameters to object's properties. It also checks type of property and parameters to match. If there is no match found, then default value will be passed to this parameterized constructor.


1 Answers

I put together a sample converter to point you in the right direction. Here are my sample JSON strings:

{geometryType: "esriGeometryPolygon", geometry: { rings: 5 } }

{geometryType: "esriGeometryOther", geometry: { rings: 5 } }

I tested it like this:

var serializer = new JsonSerializer(); var geometry = serializer.Deserialize<Geometry>(new JsonTextReader(new StringReader(jsonData)));  //Should have correctly typed instance here... 

And here is the converter and sample geometry objects:

public class GeometryConverter : JsonConverter {     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)     {         throw new NotImplementedException();     }      public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)     {         if (reader.TokenType == JsonToken.Null)             return null;          reader.Read(); // startobject          //we should be at geometry type property now         if ((string)reader.Value != "geometryType") throw new InvalidOperationException();          reader.Read(); //propertyName          var type = (string)reader.Value;          Geometry value;          switch(type)         {             case "esriGeometryPolygon":                 value = new PolygonGeometry();                 break;             case "esriGeometryOther":                 value = new OtherGeometry();                 break;             default:                 throw new NotSupportedException();         }          reader.Read(); // move to inner object property         //should probably confirm name here          reader.Read(); //move to inner object          serializer.Populate(reader, value);          reader.Read(); //move outside container (should be end object)          return value;     }      public override bool CanConvert(Type objectType)     {         return typeof(Geometry).IsAssignableFrom(objectType);     } }  [JsonConverter(typeof(GeometryConverter))] public class OtherGeometry : Geometry {  }  [JsonConverter(typeof(GeometryConverter))] public class PolygonGeometry : Geometry {  }  [JsonConverter(typeof(GeometryConverter))] public class Geometry {     public int rings { get; set; } } 
like image 87
Paul Tyng Avatar answered Sep 22 '22 06:09

Paul Tyng