Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize json with auto-trimming strings

I use Newtonsoft.Json library

Is there a way to trim spaces from any string data during deserialization?

class Program
{
    class Person
    {
        [JsonProperty("name")]
        public string Name;
    }
    static void Main(string[] args)
    {
        var p = JsonConvert.DeserializeObject<Person>(@"{ name: "" John "" }");
        Console.WriteLine("Name is: \"{0}\"", p.Name);
    }
}

Added:

Finally, I've got solution with custom converter. Not nice, but better then property with Trim().

If anyone has any ideas how to do it in more natural way, please welcome.

class Program
{
    sealed class TrimAttribute : Attribute
    { }

    class TrimConverter<T> : JsonConverter where T : new()
    {
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            var jObject = JObject.Load(reader);
            var obj = new T();
            serializer.Populate(jObject.CreateReader(), obj);

            var props = objectType.GetFields(BindingFlags.Instance | BindingFlags.Public)
                .Where(p => p.FieldType == typeof(string))
                .Where(p => Attribute.GetCustomAttributes(p).Any(u => (Type) u.TypeId == typeof(TrimAttribute)))
                ;

            foreach (var fieldInfo in props)
            {
                var val = (string) fieldInfo.GetValue(obj);
                fieldInfo.SetValue(obj, val.Trim());
            }

            return obj;
        }

        public override bool CanConvert(Type objectType)
        {
            return objectType.IsAssignableFrom(typeof (T));
        }
    }

    [JsonConverter(typeof(TrimConverter<Person>))]
    class Person
    {
        [JsonProperty("name")]
        [Trim]
        public string Name;

        [JsonProperty("surname")]
        public string Surname;
    }
    static void Main(string[] args)
    {
        var p = JsonConvert.DeserializeObject<Person>(@"{ name: "" John "", surname: "" Smith "" }");
        Console.WriteLine("Name is: \"{0}\", \"{1}\"", p.Name, p.Surname);
    }
}
like image 389
Sam Fisher Avatar asked Oct 09 '13 12:10

Sam Fisher


People also ask

How do you convert a JSON string to a JSON deserialization?

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 Deserialized JSON?

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).

Is JSON deserialization slow?

The expected latency when downloading anything from a server to a client should increase as the size of the file increases.

How does JSON deserialization work?

In Deserialization, it does the opposite of Serialization which means it converts JSON string to custom . Net object. In the following code, it creates a JavaScriptSerializer instance and calls Deserialize() by passing JSON data. It returns a custom object (BlogSites) from JSON data.


2 Answers

You could write your own JsonConverter:

public class TrimmingConverter : JsonConverter
{
    public override bool CanRead => true;
    public override bool CanWrite => false;

    public override bool CanConvert(Type objectType) => objectType == typeof(string);

    public override object ReadJson(JsonReader reader, Type objectType,
                                    object existingValue, JsonSerializer serializer)
    {
        return ((string)reader.Value)?.Trim();
    }

    public override void WriteJson(JsonWriter writer, object value, 
                                   JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

You can use it like this to apply to all string fields:

var json = @"{ name:"" John "" }"
var p = JsonConvert.DeserializeObject<Person>(json, new TrimmingConverter());
Console.WriteLine("Name is: \"{0}\"", p.Name);
//Name is: "John"

Or you can apply this to certain fields only:

public class Person
{
    [JsonProperty("name")]
    [JsonConverter(typeof(TrimmingConverter))] // <-- that's the important line
    public string Name { get; set; }
    [JsonProperty("other")]
    public string Other { get; set; }
}

var json = @"{ name:"" John "", other:"" blah blah blah "" }"
var p = JsonConvert.DeserializeObject<Person>(json);
Console.WriteLine("Name is: \"{0}\"", p.Name);
Console.WriteLine("Other is: \"{0}\"", p.Other);

//Name is: "John"
//Other is: " blah blah blah "
like image 163
Tim S. Avatar answered Sep 30 '22 21:09

Tim S.


In .NET Core 3.1 you can use System.Text.Json to achieve this.

/// <summary>
/// Trim leading and trailing whitespace.
/// </summary>
public class TrimmingConverter : JsonConverter<string>
{
    /// <summary>
    /// Trim the input string
    /// </summary>
    /// <param name="reader">reader</param>
    /// <param name="typeToConvert">Object type</param>
    /// <param name="options">Existing Value</param>
    /// <returns></returns>
    public override string Read(
        ref Utf8JsonReader reader,
        Type typeToConvert,
        JsonSerializerOptions options) => reader.GetString()?.Trim();

    /// <summary>
    /// Trim the output string
    /// </summary>
    /// <param name="writer">Writer</param>
    /// <param name="value">value</param>
    /// <param name="options">serializer</param>
    public override void Write(
        Utf8JsonWriter writer,
        string value,
        JsonSerializerOptions options) => writer.WriteStringValue(value?.Trim());
}
like image 9
Ravi Kumar Mistry Avatar answered Sep 29 '22 21:09

Ravi Kumar Mistry