Jil icon indicating copy to clipboard operation
Jil copied to clipboard

Better control over deserialization

Open paya-cz opened this issue 6 years ago • 0 comments

Recently a lot of the JSON I need to parse looks like this:

{"prop1":"value1","prop2":"843.12","stats":[["123.45","0.01"],["567.89","599.0"],["111.11","0.07"]]}

But I need to deserialize it into classes like these:

public class A
{
    [JilDirective(Name = "prop1")]
    public string Prop1
    { get; set; }

    [JilDirective(Ignore = true)]
    public decimal Prop2
    { get; set; }

    [JilDirective(Ignore = true)]
    public List<B> Stats
    { get; set; }
}

internal class JilA : A
{
    [JilDirective(Name = "prop2")]
    public string JilProp2
    {
        get => throw new NotImplementedException();
        set => this.Prop2 = decimal.Parse(value);
    }

    [JilDirective(Name = "stats")]
    public List<List<string>> JilStats
    {
        get => throw new NotImplementedException();
        set
        {
            var result = new List<B>(value.Count);

            for (int i = 0; i < value.Count; i++)
            {
                var value1 = decimal.Parse(value[i][0]);
                var value2 = decimal.Parse(value[i][1]);
                result.Add(new B { Value1 = value1, Value2 = value2 });
            }

            this.Stats = result;
        }
    }
}

public class B
{
    public decimal Value1
    { get; set; }

    public decimal Value2
    { get; set; }
}

Notice I have to write a special deserialization class JilA and deserialize a lot of the data myself. I do not see a way how to convert the above JSON into the data structure I need in more "native Jil" way. Is there?

Other solution I tried is also writing a special TextReader, which wraps the real JSON TextReader and basically waits until it sees "stats":[ in the Read() procedure, and it hallucinates/rewrites a bunch of data to basically seamlessly rewrite the above JSON into:

{"prop1":"value1","prop2":843.12,"stats":[{"Value1": 123.45,"Value2":0.01},{"Value1":567.89,"Value2":599.0},{"Value1":111.11,"Value2":0.07}]}

But it is very error prone and all I do is just looking for the right bytes in the data rather than parsing the JSON in a safe manner.

Anyway, these sort of problems with having to write my own deserialization class JilA are fairly common, because most of the financial API I have been working with return the stats data in a condensed nested array format rather than writing the data in array of objects.

So, I envision the following enhancement:

public class A
{
    [JilDirective(Name = "prop1")]
    public string Prop1
    { get; set; }

    [JilDirective(Name = "prop2", UnderlyingType = JilUnderlyingTypes.String)]
    public decimal Prop2
    { get; set; }

    [JilDirective(Name = "stats")]
    public List<B> Stats
    { get; set; }
}

[JilDirective(UnderlyingType = JilUnderlyingTypes.Array)]
public class B
{
    [JilDirective(ArrayOffset = 0, UnderlyingType = JilUnderlyingTypes.String)]
    public decimal Value1
    { get; set; }

    [JilDirective(ArrayOffset = 1, , UnderlyingType = JilUnderlyingTypes.String)]
    public decimal Value2
    { get; set; }
}

Where I can specify the UnderlyingType, to instruct Jil that the decimals are wrapped in quotes. I can also change an object B to be stored as array rather than object, and then use ArrayOffset to specify property positions within that array.

I guess I could use dynamic deserialization to solve these problems, but probably with a major performance cost?

paya-cz avatar Feb 08 '18 09:02 paya-cz