10 May 2019

Migrating to MRTK2–NewtonSoft.JSON (aka JSON.Net) is gone

Intro

In ye olde days, if you set up a project using the Mixed Reality Toolkit 1, NewtonSoft.JSON (aka JSON.Net) was automatically included. This was because part of the MRTK1 had a dependency on it –something related to the gLTF stuff used it. This is (apparently) no longer the case. So if you had a piece of code that previously used something like this

public class DeserializeJson : MonoBehaviour
{
    [SerializeField]
    private TextMeshPro _text;

    void Start()
    {
        var jsonstring = @"
{
   ""Property1"" : ""Hello"",
   ""Property2"" : ""Folks""
}";
        var deserializedObject = JsonConvert.DeserializeObject<DemoJson>(jsonstring);

        _text.text = string.Concat(deserializedObject.Property1,
            Environment.NewLine, deserializedObject.Property2);
    }
}

It will no longer compile when you use the MRTK2. You will need to get it elsewhere. There are two ways to solve this: the right way and the wrong way.

The wrong way

The wrong way, that I was actually advised to do, is to get a copy of an MRTK1 and drag the JSON.Net module from there into your project. It's under HoloToolkit\Utilities\Scripts\GLTF\Plugins\JsonNet. And it will appear to work, too. In the editor. And as long as you use the .NET scripting backend. Unity has announced, though, the .NET backend will disappear – you will need to use IL2CPP soon. And when you do so, you will notice your app will mysteriously fail to deserialize JSON. If you run the C++ app in debug mode from Visual Studio you will see something cryptic like this:

The reason why is not easy to find. If you dig deeper, you will see it complaining about it trying to use Reflection.Emit and this apparently is not allowed in the C++ world. Or not in the way it's done. Whatever.

The right way

Fortunately there is an another way - and a surprisingly one to boot. There is a free JSON.Net package in the Unity store, and it seems to do the trick for me – I can compile the C++ app, deploy it on the HoloLens 2 emulator and it actually parses JSON.

QED:

But will this work on a HoloLens 2?

The fun thing is of course the HoloLens 2 has an ARM processor, so the only way to test if this really works is to run in on an HoloLens 2. Unlike a few very lucky individuals, I don't have access to the device. But I do have something else - an ARM based PC that I was asked to evaluate in 2018.  I compiled for ARM, made a deployment package, powered up the ARM PC and wouldn't you know it...

So. I think we can be reasonably sure this will work on a HoloLens 2 as well.

Update - this has been verified.

Conclusion

I don't know whether all the arcane and intricate things JSON.Net supports are supported by this package, but it seems to do the trick as far as my simple needs are concerned. I guess you should switch to this package to prepare for HoloLens 2.

Code as usual on GitHub:

And yes, the master is still empty but I intend to use that for demonstrating a different issue.

3 comments:

Unknown said...

Joost, as I understand it, the newtonsoft json.net version in the gltf downloader (the one from the asset store, don't know if this is the same or a little newer version than the version in MRTK1) uses .NET 3.5 and the json.net one you downloaded from the store is the .NET 4.5 version (both adapted for Unity).

Since I use extensively the gltf loader, I will stick with the .NET 3.5 version as long as I can. The question I have for you is why the older version will not compile together with MRTK2?

Grtz, Tom Mensink

Joost van Schaik said...

@Tom - it will compile fine. That is not the issue. It will crash run time because apparently it uses Reflection.Emit under the covers and apparently this in not allowed in the generated C++ solution, as I explain in the text. And I have tried to generate a C# deployment solution with the MRTK2 - and could not get that to compile. So I decided to move forward with this version

Unknown said...

Joost, this is all very confusing. As I understand it after doing a number of tests:

- MRTK1, uses json.net .net version 3.5 in its gltf component. This compiles fine and also runs fine on UWP with IL2CPP. That is as long as you DON'T use dynamics, JObject, JArray, basically the Newtonsoft.Json.Linq stuff. This will compile, yet generate Reflection.Emit errors. This is caused by C++ which does not store variable names.

- MRTK2, does not compile with json.net version 3.5 according to you. WHY? You downloaded json.net 4.5 and it compiles and runs correctly. But that is still only true if you do not use dynamcis, because it is still translated to C++ with IL2CPP.

There should be no difference with the json.net .net 3.5 and .net 4.0 versions other than that you can use more fancy stuff in .net 4.0 version like x.y instead of x["y"] in your code.

Basically it should have nothing to do with MRTK1 or MRTK whether you get Reflection.Emit errors. This does depend on whether you are trying to deserialize typed versus untyped json. For typed json you can use any version of json.net, but why then do you not use the build-in Unity json version: JsonUtility.FromJson(jsonstring). This works very good. For untyped json (untyped = you do not know the key values in advance), there is currently no solution for UWP that I know of. The current solutions all use reflection.Emit.

So what I am curious is why json.net version 3.5 does not compile with MRKT2. I will investigate this, have to start at some time with HL2 stuff anyway :-) Will let you know