Json Deserialized example

Support for float and double has been added in pull request 475

There’s also a fix for processing of DateTime serialization and deserialization which was causing exceptions under some conditions.

This is the test code that I used:

using System;
using System.Diagnostics;

using GHIElectronics.TinyCLR.Data.Json;

namespace TinyCLRApplication3
{
    public class ChildClass
    {
        public int one;
        public int two;
        public int three;
    }

    public class TestClass
    {
        public int i;
        public float f;
        public double d;
        public string aString;
        public string someName;
        public DateTime Timestamp;
        public int[] intArray;
        public string[] stringArray;
        public ChildClass child1;
        public ChildClass Child { get; set; }
    }

    class Program
    {
        static void Main()
        {
            DoArrayTest();
            DoDoubleTest();
            DoSimpleObjectTest();
            DoComplexObjectTest();
        }

        private static void DoArrayTest()
        {
            int[] intArray = new[] { 1, 3, 5, 7, 9 };

            var result = JsonConverter.Serialize(intArray);
            var bson = result.ToBson();
            var compare = JsonConverter.FromBson(bson, typeof(int[]));
            if (!ArraysAreEqual(intArray, (Array)compare))
                throw new Exception("array test failed");
            Debug.WriteLine("Array test succeeded");
        }

        private static void DoDoubleTest()
        {
            double[] dArray = new[] { 1, 3, 5, double.NaN, 9 };

            var result = JsonConverter.Serialize(dArray);
            var bson = result.ToBson();
            var compare = JsonConverter.FromBson(bson, typeof(double[]));
            if (!ArraysAreEqual(dArray, (Array)compare))
                throw new Exception("array test failed");
            Debug.WriteLine("Array test succeeded");
        }

        private static void DoSimpleObjectTest()
        {
            var source = new ChildClass()
            {
                one = 1,
                two = 2,
                three = 3
            };

            var serialized = JsonConverter.Serialize(source);
            var bson = serialized.ToBson();
            var compare = (ChildClass)JsonConverter.FromBson(bson, typeof(ChildClass));
            if (source.one != compare.one ||
                source.two != compare.two ||
                source.three != compare.three)
                throw new Exception("simple object test failed");
            Debug.WriteLine("simple object test passed");
        }

        private static void DoComplexObjectTest()
        {
            var test = new TestClass()
            {
                aString = "A string",
                i = 10,
                f = 3.1415925f,
                d = 2 * 3.1415925,
                someName = "who?",
                Timestamp = DateTime.UtcNow,
                intArray = new[] { 1, 3, 5, 7, 9 },
                stringArray = new[] { "two", "four", "six", "eight" },
                child1 = new ChildClass() { one = 1, two = 2, three = 3 },
                Child = new ChildClass() { one = 100, two = 200, three = 300 }
            };
            var result = JsonConverter.Serialize(test);
            Debug.WriteLine("Serialization:");
            var stringValue = result.ToString();
            Debug.WriteLine(stringValue);

            var dserResult = JsonConverter.Deserialize(stringValue);
            Debug.WriteLine("After deserialization:");
            Debug.WriteLine(dserResult.ToString());

            var newInstance = (TestClass)JsonConverter.DeserializeObject(stringValue, typeof(TestClass), CreateInstance);
            if (test.i != newInstance.i ||
                test.f != newInstance.f ||
                test.d != newInstance.d ||
                test.Timestamp.ToString() != newInstance.Timestamp.ToString() ||
                test.aString != newInstance.aString ||
                test.someName != newInstance.someName ||
                !ArraysAreEqual(test.intArray, newInstance.intArray) ||
                !ArraysAreEqual(test.stringArray, newInstance.stringArray)
                )
                throw new Exception("complex object test failed");

            // bson tests
            var bson = result.ToBson();
            var compare = JsonConverter.FromBson(bson, typeof(TestClass), CreateInstance);
        }

        private static object CreateInstance(string path, string name, int length)
        {
            if (name == "intArray")
                return new int[length];
            else if (name == "stringArray")
                return new string[length];
            else
                return null;
        }

        private static bool ArraysAreEqual(Array a1, Array a2)
        {
            if (a1 == null && a2 == null)
                return true;
            if (a1 == null || a2 == null)
                return false;
            if (a1.Length != a2.Length)
                return false;
            for (int i = 0; i < a1.Length; ++i)
            {
                if (!a1.GetValue(i).Equals(a2.GetValue(i)))
                    return false;
            }
            return true;
        }
    }
}
6 Likes

Hmmmm - I’m noticing that my test only represents scalar values as fields. If you wrap your scalars in properties (e.g., with { get; set; }) then things break when the code tries to serialize those things as JProperty items.

Need to amend the PR I guess…

UPDATE: Ok, this is fixed. Properties now serialize and deserialize properly, and float and double
are handled correctly in both cases. The PR has been updated. By the way, property serialization
is the problem that was causing the exception that @Phil_C was seeing.

3 Likes

Corrected version is working very fine.
Thanks !!!

Now I can have a meteo station working on my SC20260D !!!

5 Likes

Is it possible to serialize / deserialize numbers of type long? Throws an exception for me

#### Exception System.Exception - CLR_E_WRONG_TYPE (1) ####
#### Message: 
#### System.Reflection.FieldInfo::SetValue [IP: 0000] ####
#### GHIElectronics.TinyCLR.Data.Json.JsonConverter::PopulateObject [IP: 014f] ####
#### GHIElectronics.TinyCLR.Data.Json.JsonConverter::DeserializeObject [IP: 000c] ####
#### SC20260_AWS_Test_01.Program::Main [IP: 008f] ####
Ausnahme ausgelöst: "System.Exception" in mscorlib.dll
Ein Ausnahmefehler des Typs "System.Exception" ist in mscorlib.dll aufgetreten.

There were a lot of json fixes that went into Preview5. Are you using Preview5? If you are and it is still failing, I will dig in and get it fixed.

Thanks, yes, I used preview5

Filed as https://github.com/ghi-electronics/TinyCLR-Libraries/issues/540

I will take a look at it shortly.

3 Likes

Hi @mcalsyn, is it possible you can answer the issue in your original repo? It would be really helpful either way… Many thanks, Robin.

It’s certainly possible to do that, but that’s going to be down a ways in my priority stack, so it may take me a while to get to that. My focus right now is on TinyCLR and some commercial projects there. I need to find time to set up a netmf test environment to do that back-porting.

In the meantime, you could grab all the .cs files from the TinyCLR library, as they are open-source, and just include those .cs files directly in your project as source.

1 Like

Thanks for your answer. If I just create a PR that only changes the header in your repo so you can merge it, since that is the original source (that removes the issue with the header, or removes it altogether) is that okay? let me know which one you prefer…

BTW, the only reason the PR was raised, was to satisfy the Iicense issue (that was raised against the repo issue #1)… If the header is removed from the source, there is no real reason for the PR…

Oh - yeah - my bad for not cleaning that up that header long ago when the library went open-source.

Yes, I will consider any PR and am grateful for the help.

Do wait for the next checkin (probably today) that fixes the numeric issue that RoSchmi found. It’s more serious than it looks there. The JSON spec says that all numbers are 'double’s, but of course that’s not true of the C# types one might be populating in an object, so I had to add a bunch more type coercion code and some BSON and array marshalling fixes. I’m pretty close to having it worked out.

2 Likes

I will try to get a PR that makes the header of the source files done to make the license clear as to open source ASAP. Given the amount of changes needed for nanoFramework (and to an extent TinyCLR), precompiler statements get too complex (and I do have an example). Also, it is worth considering (if you haven’t already) float.NaN and double.NaN… both of these do not have a place in Json, but are used regularly by sensors… Here is an example: https://stackoverflow.com/questions/1423081/json-left-out-infinity-and-nan-json-status-in-ecmascript although in our enterprise application, we just change them to null !

Done, see https://github.com/PervasiveDigital/jsonnetmf/pull/3

How do we make sure the changes make it into TinyCLR?

It PR only changes the header (as technically even TinyCLR is possibly in breach of the license)…

When that is solved (so I can upload the source), feel free to “borrow” any improvements I (and other have made) to the lib ;-p…

We got permission in writing right from the author :wink:

As long as it is in writing, and all of your users also have a statement that perpetuates the license to them… (a company I work for has just suffered the consequences of that)… but also any netMF project that uses the source (especially since they could take the changes from TinyCLR libs, and still be subject to the licence conditions in the original repo)…

Edit: would be solved by the PR anyhow…

Yeah - Gus was super careful about getting this right, and I really appreciate that. We’ll get the headers cleared up and make sure the license is more clear in the Pervasive Digital repo. FWIW, and for the world to hear, y’all have a perpetual, non-exclusive right to do whatever you please with the code. Hope you find it useful. I’m really happy to see it become part of TinyCLR.

2 Likes

Santa will come your way this Christmas for being a good boy :wink: thanks for everything