mgholam / fastJSON

Smallest, fastest polymorphic JSON serializer
https://www.codeproject.com/Articles/159450/fastJSON-Smallest-Fastest-Polymorphic-JSON-Seriali
MIT License
479 stars 147 forks source link

Heterogeneous arrays #86

Closed arekbulski closed 4 years ago

arekbulski commented 6 years ago

Could someone point out to me, even in speculation or educated guess, if this could be done using fastJSON or other framework?

I have a heterogeneous array like [1, 2.0, "3"].

Can this be somehow (de)serialized using a class?

class HeteroArray
{
  public int A;
  public double B;
  public string C;
}
mgholam commented 6 years ago

You can't deserialize an array into an object, but you can have a object[] :

var o = JSON.ToObject("[1,\"2\",3.141592]");
// o[0] == 1 long
// o[1] == "2" string
// o[2] == 3.141592 double
arekbulski commented 6 years ago

I made a mistake in previous example, it would need to be a decimal (not double). Could a decimal be parsed in your example code, directly, without converting from a double?

mgholam commented 6 years ago

Without type information fastJSON assumes it to be a double, if you need decimal then you should convert it afterwards.

mgholam commented 6 years ago

Hmmm... looking at the parse code, it should be a decimal since it does not have an exponent, I have changed fastJSON and the tests pass, will post soon.

arekbulski commented 6 years ago

I was thinking of using a custom transform like this one:

class HeterogenousArray : JsonConverter<HeteroArray, object[]>
{
    protected override object[] Convert (string fieldName, HeteroArray fieldValue) {...}
    protected override HeteroArray Revert (string fieldName, object[] fieldValue) {...}
}

I had done some experiments with Newtonsoft but well, it sort of worked. It worked correctly on simple examples but failed in more complex structures. But it is essentially what I had in mind.

using System;
using System.Reflection;
using System.Runtime.InteropServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

namespace HeterogenousArraysLab
{
    class Program
    {
        static void Main(string[] args)
        {
            var x = JsonConvert.DeserializeObject<Example>("[1.2, true, \"text\"");
            var json = JsonConvert.SerializeObject(x);
        }

        public class HeterogenousArray: JsonConverter
        {
            public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
            {
                var objectType = value.GetType();

                writer.WriteStartArray();
                foreach (FieldInfo member in objectType.GetFields(BindingFlags.Public | BindingFlags.Instance))
                {
                    writer.WriteValue(member.GetValue(value));
                }
                writer.WriteEndArray();
            }

            public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
            {
                var ctor = objectType.GetConstructor(Type.EmptyTypes);
                var obj = ctor.Invoke(new object[]{});

                foreach (FieldInfo member in objectType.GetFields(BindingFlags.Public | BindingFlags.Instance))
                {
                    if (reader.Read() == false)
                        throw new Exception("Not enough JSON fields to match type fields.");

                    member.SetValue(obj, reader.Value);
                }

                if (reader.Read() == true)
                    throw new Exception("Too many JSON fields to match type fields.");

                return obj;
            }

            public override bool CanConvert(Type objectType)
            {
                return objectType.IsClass && objectType.IsLayoutSequential;
            }
        }

        [JsonConverter(typeof(HeterogenousArray))]
        [StructLayout(LayoutKind.Sequential)]
        class Example
        {
            public double Number;
            public bool TrueValue;
            public string Text;
        }
    }
}
arekbulski commented 6 years ago

Would you be willing and able to merge a PR adding support for heterogenous arrays into the core library? I am a maintainer on GitHub as well, Construct library for Python, so I can promise you clean code and test cases.

mgholam commented 6 years ago

You can always fork fastJSON and add your own code to it :)

arekbulski commented 6 years ago

Yeah true :) but I would like to pull it via NuGet. Was that a no?