Search Unity

JSON .NET for Unity

Discussion in 'Assets and Asset Store' started by Dustin-Horne, Sep 13, 2013.

  1. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    I think you should check the installation again. jilleJr is using the 12.0.1 version of Newtonsoft.Json, not 8.0.0.
    https://github.com/jilleJr/Newtonsoft.Json-for-Unity#installation-via-upm

    (And dont' forget to add a link.xml which includes a fully qualified assembly name)
    Code (csharp):
    1. <linker>
    2.     <assembly fullname="Newtonsoft.Json, Version=12.0.1.0, Culture=neutral, PublicKeyToken=null" preserve="all"/>
    3. </linker>
    I've made a test for WebGL.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3. using TMPro;
    4. using Newtonsoft.Json;
    5. using Newtonsoft.Json.Converters;
    6.  
    7. namespace Dev
    8. {
    9.     public class TestBehaviour : MonoBehaviour
    10.     {
    11.         [SerializeField]
    12.         private TextMeshProUGUI firstText = null;
    13.  
    14.         [SerializeField]
    15.         private TextMeshProUGUI secondText = null;
    16.  
    17.         private void Start()
    18.         {
    19.             var settings = new JsonSerializerSettings {
    20.                 ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    21.                 Formatting = Formatting.Indented
    22.             };
    23.  
    24.             var myClass = new MyClass {
    25.                 myReadonlyStruct = new MyReadonlyStruct(123, new Vector3(1, 5, 6), MyEnum.C)
    26.             };
    27.  
    28.             myClass.myDictionary.Add(19, "the key is 19");
    29.             myClass.myDictionary.Add(88, "the key is 88");
    30.  
    31.             this.firstText.text = JsonConvert.SerializeObject(myClass, settings);
    32.             var obj = JsonConvert.DeserializeObject<MyClass>(this.firstText.text, settings);
    33.             this.secondText.text = JsonConvert.SerializeObject(obj, settings);
    34.         }
    35.  
    36.         [JsonConverter(typeof(StringEnumConverter))]
    37.         public enum MyEnum
    38.         {
    39.             A, B, C, D, E
    40.         }
    41.  
    42.         public class MyClass
    43.         {
    44.             public MyReadonlyStruct myReadonlyStruct { get; set; }
    45.  
    46.             public Dictionary<int, string> myDictionary { get; } = new Dictionary<int, string>();
    47.         }
    48.  
    49.         public readonly struct MyReadonlyStruct
    50.         {
    51.             public readonly int id;
    52.             public readonly Vector3 vector3;
    53.             public readonly MyEnum myEnum;
    54.  
    55.             public MyReadonlyStruct(int id, Vector3 vector3, MyEnum myEnum)
    56.             {
    57.                 this.id = id;
    58.                 this.vector3 = vector3;
    59.                 this.myEnum = myEnum;
    60.             }
    61.         }
    62.     }
    63. }
    And the result:
    upload_2019-11-20_17-23-15.png
     
    jilleJr likes this.
  2. Neonlyte

    Neonlyte

    Joined:
    Oct 17, 2013
    Posts:
    516
    Just want to post here for future references:

    Unity now supports full .NET Standard 2.0. You don't have to use this AOT implementation of an old JSON.NET, and instead start using the official DLL. You can go download the nuget package, unzip it, and extract the netstandard20 DLL for either .NET 4.6 or .NET Standard API compatibility in Unity.

    The only difference is the missing Unity type converters (the AOT impl. author added those himself <3). You can single out the source code and include it in your project.
     
    hottabych likes this.
  3. KevinCodes4Food

    KevinCodes4Food

    Joined:
    Dec 6, 2013
    Posts:
    61
    If anyone else is trying out WebGL with Newtonsoft JSON and .Net Standard 2.0 libraries, you might be interested in our experiences.

    We have been building out a Unity 2019 WebGL, iOS, and Android project that has a large amount of code in shared .Net Standard 2.0 libraries. These libraries utilize Newtonsoft.Json 12.0.1 extensively.

    We tried using the Newtonsoft.Json netstandard20 DLL based on Neonlyte's excellent advice above. It ran fine in the editor, but we hit a number of run-time exceptions in the WebGL builds when serialization/deserialization was attempted. The exceptions failed on missing constructors and properties, even though they were clearly in the library classes and had been marked as JsonConstructors and JsonProperties.

    We were stuck for quite a while on the missing JSON constructor issue. We were very concerned we would be facing major rewrites of large sections of .Net Standard code shared across several other projects. Pretty depressing.

    Luckily, I found a great article on WebGL from Masashi Nakane with some crucial JSON hints at https://blog.indiesquare.me/the-way-to-unity-webgl-support-acb4984bf705. Based on Masashi Nakane's notes related to IL2CPP stripping and the instructions at https://docs.unity3d.com/ScriptReference/Scripting.PreserveAttribute.html I added a new preserve attribute in our shared .Net Standard libraries:
    Code (CSharp):
    1. [System.AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Constructor)]
    2. public class PreserveAttribute : System.Attribute
    3. {
    4. }

    Next, we used the attribute on JSON constructors in the shared libraries that were failing to serailize/deserialize as follows:
    Code (CSharp):
    1. [PreserveAttribute]
    2. [JsonConstructor]
    3. public PlayerData(string name="", int value=0)
    4. {
    5.    ...
    6. }

    With this fix, Newtonsoft.Json 12.0.1 in .Net Standard 2.0 libraries is working for us in WebGL builds.

    P.S. Probably the last one to figure this out, but it was a great help turning on Unity 2019’s Player Settings -> Publishing Settings -> Full With Stacktrace as well as turning on Debug Symbols in that same menu for development builds. This gives clear indictment of the place where your code fails during WebGL development with a clear, easy to read stack.
     
    Last edited: Dec 7, 2019
    aer0ace, shifugate and mandisaw like this.
  4. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    You should use this solution.

     
  5. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    Since Unity is moving to the Package Manager solution (hence the name UPM), I think you should explore this functionality a bit. Installing a package via UPM is already the simplest. You just need to read the section "Installation via UPM" on that github page: https://github.com/jilleJr/Newtonsoft.Json-for-Unity#installation-via-upm

    (Using UPM, you don't have to manually download & extract anything into the Assets folder anymore.)

    For the link.xml part, you need to understand the "bytecode stripping" of Unity when build for AOT platforms.
    https://docs.unity3d.com/Manual/IL2CPP-BytecodeStripping.html

    TLDR; The link.xml is just a file name "link.xml" that you put into the Assets folder. The content of that file is what I've already provided above. That file will let Unity know that it should preserve ALL the code in Newtonsoft.JSON.dll when build the game. Without this link.xml file, many functionality of Newtonsoft.JSON.dll will be stripped and it will fail to operate on AOT platforms such as iOS, WebGL.

    Newtonsoft.JSON is just a specific case you'd need to be aware of bytecode stripping and link.xml. There are many other libraries that depend on the generic codes which usually will be stripped aggressively and silently by Unity. If you aren't aware of this problem you might surprise at why something didn't work as expected on some platforms.

    Edit: These are the guides to Unity Package Manager
    https://docs.unity3d.com/Manual/upm-ui.html
    https://docs.unity3d.com/Manual/upm-git.html
     
    Last edited: Dec 17, 2019
    jilleJr likes this.
  6. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    You must delete the old installation and use UPM instead.

    Though, a word of caution since you said you are new to serialization(?):
    That the version from asset store comes with some custom converters for serializing Unity types (like Vector2, Vector3) so the result will appear better and more efficient (since useless parts of the data will be stripped). Don't expect such behaviour from the version of Newtonsoft.JSON I suggest you to use. If you want to serialize Unity types, you must learn to write a custom converter. Or you can just use the code available here
    https://github.com/ianmacgillivray/Json-NET-for-Unity/tree/master/Source/Newtonsoft.Json/Converters

    You should read this comment of the author first if you intend to serialize Matrix4x4
    https://github.com/jilleJr/Newtonsoft.Json-for-Unity/issues/28#issuecomment-566649834

    This is somewhat a cons of this solution since you must learn more about Newtonsoft.JSON. However writing custom converters still be a must if you are required to do some advanced serialization some time later. So don't be afraid to learn a bit about it.

    The pros of the solution is, you are almost up-to-date with the original version of Newtonsoft.JSON (https://github.com/JamesNK/Newtonsoft.Json). JamesNK version is 12.0.3 atm, and jilleJr's version is 12.0.1 and soon will be updated, while the one from asset store is 8.0 which is very out of date now.

    Edit: And I'm sorry I cannot reply to that last part of your reply, is it an intended joke? I surely come from another part of the world so I just don't get it. No hard word though :D
     
    Last edited: Dec 18, 2019
    mmilan likes this.
  7. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    So you should get familiar to it as soon as possible. Working with client and server this knowledge is indispensable.
     
  8. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    Well, I just don't have any answer to this question.

    For myself, I'm already moving away from the asset store when it comes to open source tools and libraries. I prefer to use UPM because I can keep a lot of 3rd party code away from my actual project, hence greatly reduce the reloading time of Visual Studio. Actually, I cannot do that for everything, there are some tools don't work well with UPM atm, or proprietary tools which I cannot host openly on github or somewhere else.

    Unity promises an ability of installing asset store assets via UPM, but I don't know when it's going to happen.
     
  9. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
  10. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    I have just made some tests on my side, I built my sample (the code in comment #1751) for WebGL, Windows using Mono and Windows using IL2CPP. All builds work just fine. So I insist you looking into the Player.log to see what was going on in your build, what it was complaining about. There might be some exceptions or anything unusual.

    You should download my sample project here then make a build to see if it can run on your site with the same configuration?

    I only visit the forum some times a day so if you can't wait for my reply here, you could reach me on Discord instead. My tag is Laicasaane#5619.
     

    Attached Files:

    Last edited: Dec 19, 2019
  11. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    Because publishing to the Assets store is a hassle and a half, IMO. This whole "how to keep things up to date for your users" thing is a big problem, which Unity Package Manager (UPM) solves quite nicely with an update button. As for the settings, the package comes with a pretty extensive link.xml (as seen here: https://github.com/jilleJr/Newtonso...master/Src/Newtonsoft.Json-for-Unity/link.xml) but if you need more items to be force linked then you can add more link.xml's. They aggregate, so adding more will link both collections.

    Big kudos for telling more and more to use it <3
     
  12. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    To get around the "no ahead of time code was generated" you should use the AotHelper that comes with my package at https://github.com/jilleJr/Newtonsoft.Json-for-Unity.

    To use it, just add a call to AotHelper.EnsureList<uint>() somewhere to force the compiler to generate code for that type. As such:

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using Newtonsoft.Json.Utilities;
    4. using UnityEngine;
    5.  
    6. public class MyAotEnforcer : MonoBehaviour
    7. {
    8.     public void Awake()
    9.     {
    10.         AotHelper.EnsureList<uint>();
    11.     }
    12. }
    The beauty of it is that the script doesn't even need to be added to a GameObject. It just needs to be compiled to make the collection types to compile.

    Credit to SaladLab for the origin of this AotHelper from their Newtonsoft.Json for Unity https://github.com/SaladLab/Json.Net.Unity3D.

    Edit: There's now documentation of the AotHelper found here: https://github.com/jilleJr/Newtonsoft.Json-for-Unity/wiki/Fix-AOT-using-AotHelper

    :p

    Sounds like you're using a some other DLL that's locked on using Newtonsoft.Json 8.0.x. Check which plugins you're using in your project (maybe some converters?).

    Sidenote: there was previously an issue with the strong names (the PublicKeyToken=xxxxxx part) meaning third-party plugins could not use my built Newtonsoft.Json-for-Unity DLLs. This has been resolved in version 12.0.102.
     
    Last edited: Jan 18, 2020
    Arkade and Laicasaane like this.
  13. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    Big kudos for taking the rein maintaining this project for mankind ;)
     
    jilleJr likes this.
  14. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    Is it possible for you to provide a sample project that can demonstrate the issue? Without a sample from you I couldn't give you more help.

    In the meantime, I've just added another data class to my sample project, updated Newtonsoft.JSON package to the latest version, changed the content of "link.xml" a bit, then built the project using IL2CPP (Windows) and everything still works fine for me.

    Here is the result from both the editor and the Windows IL2CPP build
    upload_2020-1-4_20-48-10.png

    I will explain a bit about my sample here:
    Firstly, I create some data structures (class & readonly struct & generics) in C# then I serialize that C# data to JSON. It demonstrates the data transfering from client to server.

    Then, I deserialize the above JSON back to C# data to demostrate the transfering from server to client. (The deserialized data is again serialized to show on UI).

    You can see the results on left and right panels are identical which proves that my data is not lost between the processes and proves that Newtonsoft.JSON is working as expected in an IL2CPP build.
     

    Attached Files:

    Last edited: Jan 4, 2020
  15. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    This will not happen. IL2CPP is only used to bridge the gap where the Mono solution can't traverse, and they want to use Mono as much as possible as it's a full CLR. I would not be surprised if they eventually added .NET Core/.NET 5 and kick out Mono instead, but that's talking long time in the future.
     
  16. ModLunar

    ModLunar

    Joined:
    Oct 16, 2016
    Posts:
    374
    I don't know if someone's said this already, but there's good news ahead. I'm in the Unity 2020.1 Alpha (2020.1.0a23) and Newtonsoft.Json is now available as a package in the Unity Package Manager:

    upload_2020-2-18_14-28-19.png

    Just note (after getting the package) if you use .asmdefs (Assembly Definition files), you need to:

    1. Turn on the Override References checkbox
    2. Add Newtonsoft.Json.dll under Assembly References (instead of under Assembly Definition References)

    This is shown below:

    upload_2020-2-18_14-33-59.png

    This works a lot easier than it did when I tried taking the NuGet package of it from Visual Studio and trying to force it to work with Unity haha. Hope this helps :)
     
    Last edited: Feb 18, 2020
    polytropoi likes this.
  17. Player7

    Player7

    Joined:
    Oct 21, 2015
    Posts:
    1,533
  18. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
  19. Player7

    Player7

    Joined:
    Oct 21, 2015
    Posts:
    1,533
    well dur take a closer look... the other link that I posted is a third party extension of additional converters that have been made for newton json .... ie it is not https://github.com/jilleJr/Newtonsoft.Json-for-Unity which would be the same as new newton package unity has put up (no idea how well they will maintain it with newer releases)
     
  20. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    361
    My bad. I did notice the link is the converters repo, I just assumed that you'd given the wrong link. It turns out that I don't understand your question.
     
  21. Player7

    Player7

    Joined:
    Oct 21, 2015
    Posts:
    1,533
    Wasn't any question just noticed it a while back and realized it wasn't properly released yet, just posting fyi
     
    Laicasaane likes this.
  22. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    The version 1.1.2 of Unity's official package is somewhat discontinued and actually just contains the 12.0.1 .NET Standard variant of the official Newtonsoft.Json NuGet package. Their package might get some traction again. There exists a 2.0.0-preview version of Unity's package, however that one is actually the binary taken from my package (version 12.0.101). Probably as the original .NET Standard version does not fully work in IL2CPP's AOT land.

    Weird why the package is available through the Package Manager UI in Unity 2020; there's even a note in the package/~Documentation/index.md file saying:

    # Netwonsoft Json Unity Package

    ***This is a package intended for internal Unity Development Projects and as such this package is not supported. Use at your own risk.***
    I will doublecheck this. It is of course preferred to use Unity's official packages. Then payed developers can maintain a package of that sort instead of randoms like me in their free time. :)
     
    Last edited: Mar 22, 2020
  23. Player7

    Player7

    Joined:
    Oct 21, 2015
    Posts:
    1,533
    yeah I agree, wish unity had just adopted newton json in the first place back when they added json support, there implementation leaved a lot to desired in features, ended up buying the other json package because of it.
     
  24. cloverme

    cloverme

    Joined:
    Apr 6, 2018
    Posts:
    197
    Okay, this cannot be understated... a huge thank you to jilleJr

    If you are getting
     NotSupportedException: System.Reflection.Emit.DynamicMethod::.ctor 
    using IL2CPP on Windows in Unity 2019.x with .Net 4.x compatibility level and trying to do JsonConvert.DeserializeObject or other json newtonsoft call, this solution is...

    1) Remove any newtonsoft package you're already using in your project.
    2) Install this: https://github.com/jilleJr/Newtonsoft.Json-for-Unity

    This was a tough one to solve, because, there's even a post from a Unity person saying "Reflection.Emit is not supported on il2cpp platforms. o_O
     
    maewionn and jilleJr like this.
  25. VektaCo

    VektaCo

    Joined:
    Sep 30, 2019
    Posts:
    31
    How can I make populate object merge items in the same way as JsonUtility?
    Code (CSharp):
    1. //Merges Lists, etc nicely
    2. JsonUtility.FromJsonOverwrite(_JSONString, this);
    3. //Output list with Duplicate JSON Data would be A,B,C (merged)
    4.  
    5. //Does not
    6. JsonConvert.PopulateObject(_JSONString, this);
    7. //Output list with Duplicate JSON Data would be A,B,C,A,B,C (not merged)
    8.  
     
  26. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    What does the class in question look like?
    You could try use the ObjectCreationHandling.Replace setting when populating. Like this:

    Code (CSharp):
    1.  
    2. JsonConvert.PopulateObject(_JSONString, this, new JsonSerializerSettings
    3. {
    4.    ObjectCreationHandling = ObjectCreationHandling.Replace
    5. });
    6.  
     
  27. VektaCo

    VektaCo

    Joined:
    Sep 30, 2019
    Posts:
    31
    @jilleJr It is a List of objects
    lets say the objects contain a string and a float, and the string is set to [JSONignore].

    What happens when Populating is the string is set to null, and the float is loaded correctly.
    I want it to merge them, so it keeps the string values that are already set.

    *important note when using JsonUtility.FromJsonOverwrite it works.
    It just doesn't work with Json.net. I only want to use Json.net for Dictionary's.
     
  28. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    If you have JsonIgnoreAttribute applied to the member then even the ObjectCreationHandling.Replace will ignore it.

    I drafted a small example:
    https://dotnetfiddle.net/IHCyUG
     
  29. unity_XD3Dn3HR3eZlXg

    unity_XD3Dn3HR3eZlXg

    Joined:
    Jan 11, 2019
    Posts:
    1
    Same thing happened to me. Thank you.
     
  30. Xtro

    Xtro

    Joined:
    Apr 17, 2013
    Posts:
    608
    Why can't I find any of these converters in Newtonsoft.Json.Converters namespace?
     
  31. DavidBVal

    DavidBVal

    Joined:
    Mar 13, 2017
    Posts:
    206
    Hello, I am considering using this package instead of built-in Unity Json but I have a question.

    I am going to serialize my saved games, made of objects containing other objects, eventually containing primitives: floats, ints, strings, often sorted in lists or arrays. Often these objects are not initialized, but when I serialize them in Unity, they become initialized, not null anymore. Strings are empty, ints are 0, etc.

    This is a problem for me since I am assuming they are null, not "empty", plus it makes my files much bigger than they need be. Will this library be able to solve my issue?
     
  32. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    If you're going to try deserialize into Unity objects (ex GameObject, MonoBehaviours, components, etc) you're going to have a bad time with Newtonsoft.Json. deserializing those gets tricky because they live inside the scene and not just inside arbitrary memory.

    What you want to do when saving your game data is to store it in some type that does not inherit from UnityEngine.Object (again, ex: GameObject, MonoBehaviour, or any other component).

    As for the types default values, ints will always have the default value of 0; you'd have to use the nullable ints for having default value be null (in C# written `int?`). But strings have the default value of null as you want it so that's all ok.
    Unity will however default serialized string fields into empty string, which is another reason not to use UnityEngine.Object derived types.

    Also if you're microoptimizing save file size then in JSON an empty string (`""`, 2 chars) will actually have smaller footprint than a null value (`null`, 4 chars). Caring about the file size at that level is over engineering it in my opinion. Better to look into optimizing the file size after you have a working example to begin with.
     
  33. DavidBVal

    DavidBVal

    Joined:
    Mar 13, 2017
    Posts:
    206
    Thanks @jilleJr for your response.

    I am not serializing any MonoBehavior nor GameObject nor descendants. An example of what I am serializing would be:

    Code (CSharp):
    1.  
    2. [System.serializable]
    3. public class MyMainData{
    4.     public string id="ID1";
    5.     public mySubData data1;
    6.     public mySubData data2
    7. }
    8.  
    9. [System.serializable]
    10. public class MySubData{
    11.     public string string1,string2,string3,string3;
    12.     public int[20] intArray;
    13.     public List<float> listFloats;
    14. }
    This is a big simplification, of course, but should give you an idea. If I am serializing an object of the MyMainData class, and data1 and data2 are both null, I would like this serialized as

    {"id": "ID1", "data1": null, "data2": null}

    but I don't want full objects of the MySubData class with default values beign generated, which is what I am getting now.
     
  34. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    Ah gotcha! Well when accessing these values how is that done? Are you storing this MyMainData instance with a serialized field inside a MonoBehaviour? If so then probably Unity is constructing instances everywhere where you want nulls instead of class instances.
     
  35. DavidBVal

    DavidBVal

    Joined:
    Mar 13, 2017
    Posts:
    206
    The "MyMainData" object is a field from a "GenericSingleton" class object, that indeed is derived from MonoBehaviour.

    However I don't think MonoBehaviour is to blame here. I added a Debug.Log right before the serialization and saving, and another just after it, and the "MySubData" field is equal to null both times, yet in the saved file it is initialized... If it was being somehow instantiated, it would not remain null afterwards, right? This seems more like a "feature" from JSONUtility.
     
  36. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    Very strange! Newtonsoft.Json doesn't have such functionality by default. Don't think the JSONUtility package has some default override like that added.

    You can make a simple test of just new'ing up a brand new MyMainData type and serializing that into a save file and see what the result is
     
  37. RakNet

    RakNet

    Joined:
    Oct 9, 2013
    Posts:
    315
    After upgrading to Unity 2019.4.12f1 and activating IL2CPP I can no longer save or load in builds, but can save in the editor. This same code worked in Unity 2019.3.15f1 without IL2CPP. When I try to save in the build, it gives the error:

    Code (CSharp):
    1. (Filename: C:\buildslave\unity\build\Runtime/Export/Debug/Debug.bindings.h Line: 35)
    2.  
    3. Constructor on type 'System.ComponentModel.ReferenceConverter' not found.
    4. UnityEngine.Logger:Log(LogType, Object)
    5. UnityEngine.Debug:LogError(Object)
    6. DefaultSaveModule:Save(String)
    7. SaveMenuState:OnSave(Object, EventArgsTemplate)
    8. System.ComponentModel.NotifyCollectionChangedEventHandler:Invoke(Object, NotifyCollectionChangedEventArgs)
    9. ModV1.Source.InterruptableEvent`1:Invoke(Object, T)
    10. ModV1.Source.UI.Triggers.UITriggerTemplate`1:Trigger(X)
    11. UISaveMenuCanvas:OnSave(Object)
    12. System.Action`1:Invoke(T)
    13. UnityEngine.Events.InvokableCall`1:Invoke(T1)
    14. UnityEngine.Events.UnityEvent`1:Invoke(T0)
    15. UIWidgetSystem.UIWidgetButton`1:OnClickActive(PointerEventData)
    16. UIWidgetSystem.UIWidgetButton`1:_OnPointerClick(PointerEventData)
    17. System.ComponentModel.NotifyCollectionChangedEventHandler:Invoke(Object, NotifyCollectionChangedEventArgs)
    18. UnityEngine.EventSystems.ExecuteEvents:Execute(GameObject, BaseEventData, EventFunction`1)
    19. Rewired.Integration.UnityUI.RewiredStandaloneInputModule:ProcessMousePress(MouseButtonEventData)
    20. Rewired.Integration.UnityUI.RewiredStandaloneInputModule:ProcessMouseEvent(Int32, Int32)
    21. Rewired.Integration.UnityUI.RewiredStandaloneInputModule:ProcessMouseEvents()
    22. Rewired.Integration.UnityUI.RewiredStandaloneInputModule:Process()
    23. UnityEngine.EventSystems.EventSystem:Update()
    24.  
    I have already edited Packages\com.unity.nuget.newtonsoft-json@2.0.0-preview\link.xml and it previously fixed this same problem. Not sure why it no longer works

    Code (CSharp):
    1.  
    2. <linker>
    3.     <assembly fullname="System">
    4.         <type fullname="System.ComponentModel.TypeConverter" preserve="all"/>
    5.         <type fullname="System.ComponentModel.ArrayConverter" preserve="all"/>
    6.         <type fullname="System.ComponentModel.BaseNumberConverter" preserve="all"/>
    7.         <type fullname="System.ComponentModel.BooleanConverter" preserve="all"/>
    8.         <type fullname="System.ComponentModel.ByteConverter" preserve="all"/>
    9.         <type fullname="System.ComponentModel.CharConverter" preserve="all"/>
    10.         <type fullname="System.ComponentModel.CollectionConverter" preserve="all"/>
    11.         <type fullname="System.ComponentModel.ComponentConverter" preserve="all"/>
    12.         <type fullname="System.ComponentModel.CultureInfoConverter" preserve="all"/>
    13.         <type fullname="System.ComponentModel.DateTimeConverter" preserve="all"/>
    14.         <type fullname="System.ComponentModel.DecimalConverter" preserve="all"/>
    15.         <type fullname="System.ComponentModel.DoubleConverter" preserve="all"/>
    16.         <type fullname="System.ComponentModel.EnumConverter" preserve="all"/>
    17.         <type fullname="System.ComponentModel.ExpandableObjectConverter" preserve="all"/>
    18.         <type fullname="System.ComponentModel.Int16Converter" preserve="all"/>
    19.         <type fullname="System.ComponentModel.Int32Converter" preserve="all"/>
    20.         <type fullname="System.ComponentModel.Int64Converter" preserve="all"/>
    21.         <type fullname="System.ComponentModel.NullableConverter" preserve="all"/>
    22.         <type fullname="System.ComponentModel.SByteConverter" preserve="all"/>
    23.         <type fullname="System.ComponentModel.SingleConverter" preserve="all"/>
    24.         <type fullname="System.ComponentModel.StringConverter" preserve="all"/>
    25.         <type fullname="System.ComponentModel.TimeSpanConverter" preserve="all"/>
    26.         <type fullname="System.ComponentModel.UInt16Converter" preserve="all"/>
    27.         <type fullname="System.ComponentModel.UInt32Converter" preserve="all"/>
    28.         <type fullname="System.ComponentModel.UInt64Converter" preserve="all"/>
    29.         <type fullname="System.ComponentModel.ReferenceConverter">
    30.             <method signature="System.Void .ctor(System.Type)" />
    31.         </type>
    32.     </assembly>
    33.     <assembly fullname="System.Core">
    34.         <type fullname="System.Linq.Expressions.Interpreter.LightLambda" preserve="all" />
    35.     </assembly>
    36. </linker>
    37.  
     
  38. FBones

    FBones

    Joined:
    Aug 28, 2016
    Posts:
    73
    @jilleJr and @Laicasaane, I used the JSON.NET for Unity for a prototype project two years ago. I found it extremely useful.

    I'm coming back into programming with Unity now and it seems like the situations has changed now in terms of the best way of getting JSON support in Unity. What do you currently recommend, assuming I don't need to serialize Unity-specific classes? I do like the ability to serialize non-public members, though.

    Thanks in advance!
     
  39. Xtro

    Xtro

    Joined:
    Apr 17, 2013
    Posts:
    608
    I tried Unity's built-in Json serializer and it failed in some areas. Json.NET for Unity is still the best option for me.
     
  40. FBones

    FBones

    Joined:
    Aug 28, 2016
    Posts:
    73
    Thanks @Xtro , I think I'll give the ATO fork a shot in that case.
     
  41. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    I really like using Json .NET so I personally only use that one. The existing ones out in the world were kind of outdated so I created an updated one that you can load in via Unity Package Manager. My version has somehow gained some popularity, and Unity forked it and actually published it to their own package store. If you're using Unity 2020 or later, you can probably find Unity's version in the Unity Package Manager UI. If you want to use my version straight off, you can do so here: https://github.com/jilleJr/Newtonsoft.Json-for-Unity

    I've also seen a lot of people just take my built binaries and add that to their project. I personally recommend against this, as you cannot get updates that way. But I think the motive is that people want full control over their dependencies.

    I did once writeup a list of different JSON serializing alternatives to use in Unity. I'll quote myself here:

    Source: https://gist.github.com/onionmk2/d2e3e4cca27a37a89796e084e05de212#gistcomment-2973749
    Also, I apologize to any library authors I've missed in the above list.

    To summarize: it's not that easy of a decision. There is a lot to choose from. Personally, I would go with Json.NET, but when it comes to speed I would then instead probably choose Utf8Json.

    I suggest architecting your code so that the serialization is a plugin component, so you can switch serializer when you need to. Switching to protobuf or gRPC is exiting, but difficult when such an abstraction has not been made.

    Hope that answers your question :)
     
  42. FBones

    FBones

    Joined:
    Aug 28, 2016
    Posts:
    73
    I've run into a strange issue with regard to assemblies using the JSON.NET for Unity version 12.0.3 [@jilleJr 's plugin I think]. I'm hoping someone can help me.

    I have a Main assembly and another assembly for Editor Tests using Unity's Test Framework.
    Unity does not show the JSON.NET for Unity assemblies when I try to reference it:
    upload_2020-12-4_18-20-59.png

    I tried clicking the eye to have it show me the 18 hidden packages, but it did not do anything.

    So I cannot point my assemblies at the Json plugin.

    Strangely, though, the scripts in my "Main" assembly are able to see the NewtonSoft assemblies, but the scripts in my Test Assemblies are not.... even though neither of these have references to the assemblies.

    upload_2020-12-4_18-24-59.png

    upload_2020-12-4_18-25-39.png

    I'm a real newbie when it comes to messing with assemblies, but I must admit that I'm rather mystified.
     
  43. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63

    Ah yes, well there's a distinction between compiled assemblies (.DLL files) and Unity's assembly definitions (folders with source code and an .asmdef file) with how they're handled.

    The picker there you're showing in the screenshots are only for assembly definitions, while the Newtonsoft.Json assembly you want to include is just a regular compiled assembly.

    There is a way, though I do not fully remember how, that you can force override which assemblies your asmdef will reference. I do think it's just below the asmdef references.

    "Why can the "Main" asmdef access Newton soft.Json?"
    In your screenshot there it's visible that your editor tests asmdef has "Override references" enabled, while I'd assume your "Main" asmdef has that disabled which then references all assemblies automatically.

    Hope that clears something up :)
     
  44. FBones

    FBones

    Joined:
    Aug 28, 2016
    Posts:
    73
    Thanks! That worked great. Appreciate your help!
     
  45. EKG8g

    EKG8g

    Joined:
    Oct 26, 2012
    Posts:
    6
    Does Newtonsoft.Json for Unity (https://github.com/jilleJr/Newtonsoft.Json-for-Unity) support BSON?
    Or JSON .NET For Unity (https://assetstore.unity.com/packages/tools/input-management/json-net-for-unity-11347) still works?

    What I want to do is to upload/download an enormous trunk of string (serialized Unity class). So binary data (BSON) use less bandwidth, right? This is an iOS/Android project and needs to use IL2CPP and .NET 4.x to be compatible with other 3rd parties. Not sure if this is the place to ask. Any hint or suggestion?
     
    Last edited: Dec 29, 2020
    firstuser likes this.
  46. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    James Newton-King (Original author of Newtonsoft.Json) split the Newtonsoft.Json.Bson out into a separate package since Newtonsoft.Json v10.0.1.

    ParentElement's old Unity package still uses Newtonsoft.Json v8.0.1, which back then still included the BSON package, though it is still a very old version of Newtonsoft.Json, so you may be missing some features and performance improvements.

    My package does not support BSON. Well, kind of. You can use it to some degree, but the types in the Newtonsoft.Json.Bson namespace are marked with ObsoleteAttribute (even in the official Newtonsoft.Json package). It's on my todo list to setup the BSON package for Unity as well. You can follow my progress by subscribing for notifications on this issue: https://github.com/jilleJr/Newtonsoft.Json-for-Unity/issues/27

    ---

    As for the bandwidth savings: BSON shines when it comes to numbers. It can store the number 1234567890 in 4 bytes, while UTF-8 formatted JSON would take up 10 bytes (although, number 1 would still be stored as 4 bytes in BSON and only 1 byte in UTF-8 formatted JSON). When it comes to strings, BSON usually takes up more space as it prefixes its strings with the length of the string (stored as 4 byte integer) and then just uses regular UTF-8 formatting anyway. Example where JSON is more compact than BSON. This is case by case, but you'd usually only save a few percentage of bandwidth. To get the smallest bandwidth usage you could do something like a combination of BSON and some compression algo such as GZIP, though at this point you sadly have to consider and compare the cost of such an implementation and cost of just rolling with JSON.
     
  47. blablaalb

    blablaalb

    Joined:
    Oct 28, 2015
    Posts:
    53
    Is it possible to instruct JSON.NET to serialize object's property instead of the objects itself. Here's what I mean:
    I have a PlayerProgress.cs class that I serialize to json and save locally on a device. The PlayerProgress class has a reference to a Level scriptable object.
    Code (CSharp):
    1. public class PlayerProgress
    2. {
    3.     [SeializeField]
    4.     private Level _level;
    5.  
    6.     public Level Level => _level;
    7. }
    Code (CSharp):
    1. public class Level : ScriptableObject
    2. {
    3.     public int ID {get; private set;}
    4. }
    When I serialize the PlayerProgress, state of the referenced Level object is also serialized. I want to instruct JSON.NET to serialize the ID property of the Level class instead of the whole Level. So for this reason I implemented custom JsonConverter
    Code (CSharp):
    1. public class LevelSerializer : JsonConverter
    2. {
    3.     public override bool CanConvert(Type objectType)
    4.     {
    5.        return typeof(Level).IsAssignableFrom(objectType);
    6.     }
    7.  
    8.     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    9.     {
    10.         throw new NotImplementedException();
    11.     }
    12.  
    13.     public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    14.     {
    15.         Level level = value as Level;
    16.         writer.WriteStartObject();
    17.         writer.WritePropertyName("Level");
    18.         serializer.Serialize(writer, level.ID);
    19.         writer.WriteEndObject();
    20.     }
    21. }
    This is the result after the serialization:
    Code (csharp):
    1. {
    2.     "Level": {
    3.         "Level": 0
    4.     }
    5. }
    What I don't like here is that it saves the ID of the level wrapped in braces as an object. The result I'm trying to achieve should look like this:
    Code (CSharp):
    1. {
    2.     "Level": 0
    3. }
    Is it possible to achieve without changing the PlayerProgress class?
     
  48. hatzmeister

    hatzmeister

    Joined:
    Jun 5, 2018
    Posts:
    7
    Hi, I am having issues when deserializing nullable floats in a WebGl build.. It works fine in the editor but on the build I am getting an error:


    ExecutionEngineException: Attempting to call method 'Newtonsoft.Json.Utilities.CollectionWrapper`1[[System.Nullable`1[[System.Single, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]::.ctor' for which no ahead of time (AOT) code was generated. Rethrow as TargetInvocationException: Exception has been thrown by the target of an invocation. at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00000] in <00000000000000000000000000000000>:0 (Filename: currently not available on il2cpp Line: -1)



    Any fixes?

    My class contains a
    Code (CSharp):
    1. public List<List<float?>> analysisOutputData { get; set; }
    That's what causing the problem. I can't see why it works in the editor but not on the build. The json that get's deserialized will certainly contain nulls, which I need to preserve, so ignoring then via the settings is not an option.

    Many thanks
     
  49. TonismoGames

    TonismoGames

    Joined:
    Jun 12, 2018
    Posts:
    111
    @Dustin-Horne
    Hi, I am trying to parse 3 fields from a Json string so it doesn't consume a lot of memory. I have been experiencing a lot of crashes on Android with heap allocation.
    I need the field VehicleID,NickName,and CarTypeName.
    Some of my Json files contains large data, over 18 mb.
    I just want to parse these three values without having to load everything into memory.
    What would be an efficient way to do this?
    {"CarName":"20A2","Nickname":"","VehicleID":"20A224446566","Description":"","Locked":false,"Password":"","MileAge":0.0,"WeightReduction":0.0,"transmissionLayout":0,"CarIcon":{"instanceID":43884},"CarTypeName":"20A2"
     
  50. jilleJr

    jilleJr

    Joined:
    Jan 21, 2015
    Posts:
    63
    If I remember correctly the Newtonsoft.Json will only deserialize the fields that it can match. So if you create a C# class with only those three properties and deserialize your big JSON data targeting this slimmed class then it should ignore all those fields it cannot match, and thereby not consume that much memory.