Skip to content

Add Feature<T> for strongly typed (de)serialization of Feature.Properties #56

Closed

Description

@enagy27

Feature should be added such that properties can be defined by a model. There should be some support for a strongly typed version of properties. The current dictionary representation from an object breaks the use of JsonPropertyAttribute. Of course the reflection could be rewritten using GetCustomAttributes, but it would be more robust to simply use existing mechanisms.

Activity

  1. enagy27 commented on May 21, 2016

    @enagy27
    Author
    // --------------------------------------------------------------------------------------------------------------------
    // <copyright file="Feature.cs" company="Joerg Battermann">
    //   Copyright © Joerg Battermann 2014
    // </copyright>
    // <summary>
    //   Defines the Feature type.
    // </summary>
    // --------------------------------------------------------------------------------------------------------------------
    
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using GeoJSON.Net.Converters;
    using GeoJSON.Net.Geometry;
    using Newtonsoft.Json;
    
    namespace GeoJSON.Net.Feature
    {
        /// <summary>
        ///     A GeoJSON <see cref="http://geojson.org/geojson-spec.html#feature-objects">Feature Object</see>.
        /// </summary>
        public class Feature<TProperties> : GeoJSONObject
        {
            /// <summary>
            ///     Initializes a new instance of the <see cref="Feature" /> class.
            /// </summary>
            /// <param name="geometry">The Geometry Object.</param>
            /// <param name="properties">The properties.</param>
            /// <param name="id">The (optional) identifier.</param>
            [JsonConstructor]
            public Feature(IGeometryObject geometry, TProperties properties, string id = null)
            {
                Geometry = geometry;
                Properties = properties;
                Id = id;
    
                Type = GeoJSONObjectType.Feature;
            }
    
            /// <summary>
            ///     Gets or sets the geometry.
            /// </summary>
            /// <value>
            ///     The geometry.
            /// </value>
            [JsonProperty(PropertyName = "geometry", Required = Required.AllowNull)]
            [JsonConverter(typeof(GeometryConverter))]
            public IGeometryObject Geometry { get; set; }
    
            /// <summary>
            ///     Gets or sets the id.
            /// </summary>
            /// <value>The handle.</value>
            [JsonProperty(PropertyName = "id", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
            public string Id { get; set; }
    
            /// <summary>
            ///     Gets the properties.
            /// </summary>
            /// <value>The properties.</value>
            [JsonProperty(PropertyName = "properties", Required = Required.AllowNull)]
            public TProperties Properties { get; set; }
        }
    }
    
  2. joergbattermann commented on May 22, 2016

    @joergbattermann
    Member

    Feature's .Properties is a Key/Value Collection in GeoJson, and the current implementation represents that, albeit a bit ugly with the value(s) being objects in the Dictionary<string, object> type.

    However, each value in that dictionary can either be a simple value (string, int, bool etc, JValue basically), a complex json-serialized type (JObject) or a nested JArray etc etc.

    Now if it / there was a generic Feature<TProperties>, TProperties would have to be constrained to being a kv-collection, and the v(alue) type would have to be able to represent all of the above value types - so basically an object or a dynamic type (again.. to adhere the GeoJson spec).

    You can certainly create your own Feature<TPropertiesValues> and the have the Properties be i.e. an IDictionary<string, TPropertiesValues> but because the spec explicitly allows mixed value types there, I wouldn't add it to the library.

  3. enagy27 commented on May 24, 2016

    @enagy27
    Author

    I see what you mean, and I can see why this wouldn't be in the framework. In my case I'd prefer to give the flexibility to get it wrong by providing a collection and throwing an explicit exception than to accept an object and mutate it into a dictionary which is guaranteed to work. But my needs are not to necessarily adhere to the spec, so I'll do this on my own. Thanks!

  4. matt-lethargic commented on Feb 6, 2017

    @matt-lethargic
    Member

    Hey @enagy27 as you stated back in May this issue/request is more of a specific case to yourself and goes against the GeoJSON spec. I have been playing with some things to sort out the Properties deserialization thing, but it'll prob be in the code down the line some time.

    Can we close this?

  5. matt-lethargic commented on Feb 6, 2017

    @matt-lethargic
    Member

    For completeness I knocked up a crude extension method that would help in this situation. I don't normally like catching exceptions like this, but as I said, it's crude and I did it quickly

        public static class DictionaryExtensions
        {
            /// <summary>
            /// Returns typed value
            /// </summary>
            /// <param name="dictionary">Dictionary to get value from</param>
            /// <param name="key">Dictionary key of value</param>
            /// <typeparam name="T"></typeparam>
            public static T GetTypedValue<T>(this IDictionary<string, object> dictionary, string key)
                where T: class 
            {
                T typedValue;
    
                if (!dictionary.ContainsKey(key))
                    return null;
                
                try
                {
                    var value = dictionary[key];
                    typedValue = JsonConvert.DeserializeObject<T>(value.ToString());
                }
                catch
                {
                    return null;
                }
                return typedValue;
            }
        }
    
  6. enagy27 commented on Feb 7, 2017

    @enagy27
    Author

    Thanks @matt-lethargic! Yes, I'll go ahead and close this

  7. supermihi commented on Jun 4, 2017

    @supermihi
    Contributor

    I am reopening this old discussion because I am also in need for strongly typed Feature properties.

    I do understand the point that the GeoJSON spec doesn't sayn anything about a feature's properties. But if I as a library consumer know that the thing I am (de)serializing has properties of some type T, I don't see why it should be against any spec to be able to specify this knowledge.
    Basically, it's the same as with the different geometric types - the library allows Type to be any of Point, Polygon and so on, but if I know I'll be reading a Point, it is ok to write JsonConvert.DeserializeObject<Point>, isn't it?
    So, I would suggest to add a Feature<TGeometry, TProperties> class (and I am willing to create a PR) in addition to the existing weakly typed Feature class. The charm of such a class is that you can start using GeoJSON types for your business objects with specific properties, with the benefit that they can be immediately displayed in any UI / external tool that talks GeoJSON.

  8. matt-lethargic commented on Jun 6, 2017

    @matt-lethargic
    Member

    Happy to reopen this. I was only thinking about this the other day, but haven't had the time to do anything.

    @supermihi Feel free to put together a PR, I had a couple of ideas for this a while back so would love to see yours and pull them in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions