Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

JSON .NET for Unity

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

  1. vicenterusso

    vicenterusso

    Joined:
    Jan 8, 2013
    Posts:
    130
    Something is wrong here..

    My simple class: http://hastebin.com/xogegucoso.xml

    Code (csharp):
    1. var n = new Nodes {NodeList = tmpNodeList, RootLinks = rootLinksJson};
    2. var serializedObject = JsonConvert.SerializeObject(n);
    Saving is ok, but when I try to deserialize I get errors like "cant cast string to vector3".

    I also tried to remove the Dictionary and save as a serialized string too. No success.
     
  2. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Saving is actually not ok... if you look at your serialized JSON it probably isn't correct. Only primitive values are supported as dictionary keys (string, enum (which translates to string), etc). If you want to serialize a Vector3 as the key value you'll have to use a custom converter. Take a look at mcmorry's code above that is used to serialize enums as ints when doing Dictionaries. You'll have to do the same thing with Vector3.
     
  3. StephenMorris

    StephenMorris

    Joined:
    Mar 25, 2013
    Posts:
    35
    Hi there,

    Scratching my head with this one so any help is greatly appreciated.

    Code works fine testing locally within Unity but when run on an iOS device - it stops.

    Code (CSharp):
    1. int currentPlayer = 0;
    2. int incrementer = 0;
    3.  
    4. Debug.Log ("Creating Dictionary");
    5. var matchObj = new Dictionary<string, object>() {
    6.             {"CurrentPlayer", currentPlayer},
    7.             {"Score", incrementer}
    8. };
    9.      
    10. Debug.Log ("Converting to Json");
    11. var json = JsonConvert.SerializeObject(matchObj);
    When it gets to the SerializeObject, Xcode will give the following error:

    Can't really progress any further so help is greatly appreciated!
     
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Hmm... Could you try something for me... Change Line 11 so it looks like this:

    Code (csharp):
    1.  
    2. var settings = new JsonSerializerSettings();
    3. settings.TypeNameHandling = TypeNameHandling.All;
    4.  
    5. var json = JsonConvert.SerializeObject(matchObj, settings);
    6.  
    My guess is that because you have "object" specified it doesn't know what to do with it. Besides that, you wouldn't be able to properly deserialize unless you use typenamehandling to specify what the original type was. So, you'll need to use those settings when Deserializing as well. But I'm curious as to what the result is when specifying them during serialization.

    My email address is in the readme.txt file that came with the asset... drop me an email there as well and I'll give you my Skype info. I'll be leaving town tonight and won't be back until Sunday evening so hopefully this will get you fixed up right away.
     
  5. imtrobin

    imtrobin

    Joined:
    Nov 30, 2009
    Posts:
    1,548
    Hi, I see that enum are serialized to default value. I made a mistake and defined the enum name wrongly in the json, but when I deserialized, it does not throw exception error but used the default value instead. Is there a way to detect that errror?
     
  6. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Enums will be serialized to the default value because they are really treated as ints by C#. Even if you are serializing the string name of the property, as far as the values are concerned, the CLR treats them a lot like ints. I believe the library uses a TryParse when attempting to parse enums so it won't throw an exception if the name is wrong. If your property was a nullable<EnumType> then you might be able to keep the null value if the enum couldn't be resolved. If you need to transform it or treat it differently, you'd have to create a custom JsonContract to handle it.
     
  7. imtrobin

    imtrobin

    Joined:
    Nov 30, 2009
    Posts:
    1,548
    I believe the older version of the library threw an exception. In that case, how would I be able to detect errors in the json when deserializing? Especially when I read json from the web, it could get invalid json/wrong data.
     
  8. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    it didn't, not for enums. I'm out of town for the weekend but I an look when I get back. In most cases exceptions will be thrown if there's an error. By in your case the value is valid, just not a part of your enum so you end up with tue default value.
     
  9. cr4y

    cr4y

    Joined:
    Jul 12, 2012
    Posts:
    44
    Hi,
    Few day ago I've bought your package (which seams great, by the way). We had one project using XMLSerializer and throwing AOT exceptions. Then we ported it to JSON.NET and it works great (as it did before) on Windows and Mac standalone, but I'm unable to compile it for iOS. It is constantly throwing me errors:
    Cross compilation job Assembly-CSharp.dll failed.
    UnityEngine.UnityException: Failed AOT cross compiler: /Applications/Unity/Unity.app/Contents/PlaybackEngines/iOSSupport/Tools/OSX/mono-xcompiler --aot=full,asmonly,nodebug,static,outfile="Assembly-CSharp.dll.s" "Assembly-CSharp.dll" current dir : /Users/cr4y/SVN/MechaGame/Temp/StagingArea/Data/Managed
    Env: DISPLAY = '/tmp/launch-8hRuik/org.macosforge.xquartz:0'
    Apple_PubSub_Socket_Render = '/tmp/launch-b8hsYx/Render'
    LOGNAME = 'cr4y'
    TMPDIR = '/var/folders/fj/jj556qcx31559gdsts8qt5l00000gn/T/'
    MONO_PATH = '/Users/cr4y/SVN/MechaGame/Temp/StagingArea/Data/Managed'
    SSH_AUTH_SOCK = '/tmp/launch-q2uZmc/Listeners'
    USER = 'cr4y'
    GC_DONT_GC = 'yes please'
    __CF_USER_TEXT_ENCODING = '0x1F5:29:42'
    __CHECKFIX1436934 = '1'
    SHELL = '/bin/bash'
    GAC_PATH = '/Users/cr4y/SVN/MechaGame/Temp/StagingArea/Data/Managed'
    HOME = '/Users/cr4y'
    PATH = '/usr/bin:/bin:/usr/sbin:/sbin'
    result file exists: True. Timed out: False
    stdout:
    stderr: mono-xcompiler(45662,0xa05261a8) malloc: *** mach_vm_map(size=8388608) failed (error code=3)*** error: can't allocate region*** set a breakpoint in malloc_error_break to debug

    at UnityEditor.MonoProcessUtility.RunMonoProcess (System.Diagnostics.Process process, System.String name, System.String resultingFile) [0x00000] in <filename unknown>:0
    at UnityEditor.MonoCrossCompile.CrossCompileAOT (BuildTarget target, System.String crossCompilerAbsolutePath, System.String assembliesAbsoluteDirectory, CrossCompileOptions crossCompileOptions, System.String input, System.String output, System.String additionalOptions) [0x00000] in <filename unknown>:0
    at UnityEditor.MonoCrossCompile+JobCompileAOT.ThreadPoolCallback (System.Object threadContext) [0x00000] in <filename unknown>:0
    UnityEditor.HostView:OnGUI()


    I'm not sure if it is caused by your package. From other hand I had done nothing else than importing your package and porting our game to use it. Do you have any ideas what could cause that? I've already tried removing tmp,obj and Library directories, always same message. Right now I'm not sure where to search for source of problem :-(
    Thanks in advance for any help.
     
  10. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Hmm, it doesn't give you a very useful error either. This is when trying to do the build from Unity correct? I'll PM you my skype info and ill be online in a couple of hours, after I get my kids to school.
     
  11. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Version 1.4.0 has been submitted to the asset store. For those who purchased through FastSpring it will be available at parentelement.com shortly. Here is the change log for version 1.4.0:

    === Version 1.4.0 Change Log ===
    [Platform] Added Support for Windows Phone 8.1 Project
    [Platform] Added Support for Windows Store Apps 8.1 Project
    [Platform] Added Support for Windows Store Universal Project
    [Misc] Performance enhancement for iOS on Unity 4.5+ when working with collections.
    [Misc] Changed Attribute usages to fully qualified System.Attribute to avoid conflicts with any class called Attribute that is not namespaced (defined in Global Namespace).
    [Feature] Added example Converters in the Extras folder for Vector2, Vector3 and Vector4 to only serialize the x, y, z and w properties.
     
  12. argc_argv

    argc_argv

    Joined:
    Dec 14, 2013
    Posts:
    35
    Hi, the support website at unity.dustinhorne is not working.
     
  13. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Have I forgotten to update that in the documentation or asset store? It's now: http://www.parentelement.com/
     
  14. Lypheus

    Lypheus

    Joined:
    Apr 16, 2010
    Posts:
    664
    Hey, trying this out and getting an error trying to parse:

    JSON:
    {
    "Products": [
    {
    "ProductId": 1,
    "Name": "Metro Calgary"
    }
    ]
    }

    DAO:
    Code (csharp):
    1.  
    2.     public class Product
    3.     {
    4.         public long ProductId { get; set; }
    5.         public string Name { get; set; }
    6.     }
    7.  
    CODE:
    Code (csharp):
    1.  
    2. List<Product> products = JsonConvert.DeserializeObject<List<Product>>( jsonText );
    3.  
    Is the "Products" prefix throwing the library off?
     
  15. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yep. It would work if you did this:

    Code (csharp):
    1.  
    2. public class ProductList
    3. {
    4.    public List<Product> Products { get; set; }
    5. }
    6.  
    Then did this:
    Code (csharp):
    1.  
    2. var products = JsonConvert.DeserializeObject<ProductList>(jsonText);
    3.  
    You could also modify your Json to look like this:
    Code (csharp):
    1.  
    2. [
    3.    {
    4.       "ProductId": 1,
    5.       "Name": "Metro Calgary"
    6.    },
    7.    {
    8.       "ProductId": 2,
    9.       "Name": "Ottawa"
    10.    }  
    11. ]
    12.  
    You should be able to decode the above using different variants of collections (List, Array), so either of the below will work for instance:

    Code (csharp):
    1.  
    2. var prodList = JsonConvert.DeserializeObject<List<Product>>(jsonText);
    3. var prodArray = JsonConvert.DeserializeObject<Product[]>(jsonText);
    4.  
     
  16. Lypheus

    Lypheus

    Joined:
    Apr 16, 2010
    Posts:
    664
    Ah I see - so that "Products" prefix implies a wrapper class for the array!

    Works great, thanks Dustin!
     
    Last edited: Aug 25, 2014
  17. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    you're very welcome :)
     
  18. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
  19. mcmorry

    mcmorry

    Joined:
    Dec 2, 2012
    Posts:
    580
    Hi Dustin,
    I'm trying to serialize a class that has a private field and a public property to access and set it.
    I don't want that the deserialization process will execute the code to set the property. So I'd need to serialize the private field and not the public property. Is it possible?
    Thanks
     
  20. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yeah, you'll probably want to build a custom JsonConverter to do it. Does the property have both a getter and a setter? So the setter sets the value of the private field... and a getter that gets the value?
     
  21. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Ok so the easiest way is to just return the default value... so if your property is an int you want it to be zero... if it's a class you'll want it to be Null. So let's say you have a class that looks like this:

    Code (csharp):
    1.  
    2. public class MyClass
    3. {
    4.     private int _myVal;
    5.  
    6.     public int MyVal { get; set; }
    7. }
    8.  
    Now you'll want to serialize MyVal but not deserialize it. So I put together a generic converter that can be used with any type. It will return null for reference types and the default value for value types:

    Code (csharp):
    1.  
    2. public class DefaultValueConverter<T> : JsonConverter
    3. {
    4.    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    5.    {
    6.        //Just go ahead and seralize everything
    7.       serializer.Serialize(writer, value);
    8.    }
    9.    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    10.    {
    11.       return default(T);
    12.    }
    13.    public override bool CanRead
    14.    {
    15.       get { return true; }
    16.    }
    17.    public override bool CanConvert(Type objectType)
    18.    {
    19.       return objectType == typeof(T);
    20.    }
    21. }
    22.  
    So if you look at the above, for "WriteJson" it just does its thing as normal... for ReadJson it returns default(T). Now you would just change your class to have the JsonConverter attribute on your property and it will be used automatically. Here's how you assign it:

    Code (csharp):
    1.  
    2. public class MyClass
    3. {
    4.     private int _myVal;
    5.  
    6.     [JsonConverter(typeof(DefaultValueConverter<int>))]
    7.     public int MyVal { get; set; }
    8. }
    9.  
     
  22. mcmorry

    mcmorry

    Joined:
    Dec 2, 2012
    Posts:
    580
    Thank you for your detailed example. Very useful for different situations, but my problem is different.

    I have a private field, an integer, and a public property to get and set the value.
    The property has some specific code to be executed when setting the value, that raises events and accesses objects not ready during the deserialization process.
    I want to serialize and also deserialize the value, but I don't want to execute the code inside the "set" during the deserialization.
    So my idea was to serialize the private field and not the public property.
     
  23. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Oh I see what you're saying. There's still an easy way to do it.
    What you're going to want to do is explicitly use OptIn for your members and you won't add it to that one property:

    Code (csharp):
    1.  
    2. [JsonObject(MemberSerialization.OptIn)]
    3. public class MyClass
    4. {
    5.     [JsonProperty(PropertyName = "MyValue")]
    6.     private int _calculatedValue;
    7.  
    8.     private string _someOtherValue;
    9.  
    10.     public int MyValue
    11.     {
    12.         get { return _calculatedValue; }
    13.         set { _calculatedValue = Math.Max(5, value); }
    14.     }
    15.  
    16.    [JsonProperty]
    17.     public string AnotherProperty { get; set; }
    18. }
    19.  
    So the class above is pretty nonsense but enough to get the picture. First you're going to tell your class that it's OptIn which means you'll have to put [JsonProperty] on top of every property (or field) you want serialized. I showed two examples of JsonProperty.. the first which allows you to specify what the property name will be in the json string, and the second which just uses the name that's already there. So AnotherProperty will be serialized as:

    "AnotherProperty" : "value"

    and _calculatedValue will be serialized as:

    "MyValue" : 5

    And of course _someOtherValue field and the MyValue property will be ignored because they don't have the [JsonProperty] attributes specified.

    I can't remember off the top of my head whether the attributes automatically include private fields, so you may have to do this:

    Code (csharp):
    1.  
    2. var cr = new DefaultContractResolver();
    3. cr.DefaultMemberSearchFlags |= BindingFlags.NonPublic;
    4.  
    5. var settings = new JsonSerializerSettings();
    6. settings.ContractResolver = cr;
    7.  
    8. var json = JsonConvert.SerializeObject(yourObject, settings);
    9.  
    The same would apply for deserializing. The important thing to note here is that if your object has another object as a property, then it will also serialize the non-public members of that other object. There is another way that would probably allow you to avoid this. Instead of using OptIn, you would just do the following:



    Code (csharp):
    1.  
    2. public class MyClass
    3. {
    4.     [JsonProperty(PropertyName = "MyValue")]
    5.     private int _calculatedValue;
    6.  
    7.     private string _someOtherValue;
    8.    
    9.     [JsonIgnore]
    10.     public int MyValue
    11.     {
    12.         get { return _calculatedValue; }
    13.         set { _calculatedValue = Math.Max(5, value); }
    14.     }
    15.  
    16.     public string AnotherProperty { get; set; }
    17. }
    18.  
    The above is almost identical to the first example, and actually may be more simple. In this case we didn't specify "OptIn" which means that it's OptOut by default. For that field to be serialized you still have to put the [JsonProperty] attribute on it, but now you don't have to specify it for any particular properties. The difference is now we added the [JsonIgnore] attribute to the MyValue property.

    In this case, we're serializing that integer as if it were "MyValue" so it looks like it's serializing the property (we specified the name in the JsonProperty) but it's really just serializing the field. And we've explicitly ignored the actual property itself so it won't get read.
     
  24. mcmorry

    mcmorry

    Joined:
    Dec 2, 2012
    Posts:
    580
    Thank you very much for your help :)
    I'll try the second way first that seems easier and safer.
     
  25. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yeah I kind of thought of the second way as I was finish up the example for the first way. I left it just for completeness but I would definitely use the second way. :)
     
  26. imtrobin

    imtrobin

    Joined:
    Nov 30, 2009
    Posts:
    1,548
    Hi Dustin, did you find a solution to the error enum issue?
     
  27. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Are you referring to throwing an exception if the enum name is incorrect? Sorry Robin, I had forgotten about that. I'll work on a converter as soon as I get my kids to school this morning. :). It will be pretty straight forward I think.
     
  28. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Here you go Robin. This converter will cause the exception to be thrown for any enum when it has been serialized as a string and the string represents a value that is not in the enum any longer. It throws an ArgumentException if you want to trap it. The file is attached to this post (for some reason the forum editor hoses up my formatting when I copy and paste now).

    To use it you can add this to any enum properties you want to use it on:
    Code (csharp):
    1.  
    2. [JsonConverter(typeof(EnumValidationConverter))]
    3. public EnumType MyEnumProperty { get; set; }
    4.  
    You can also specify it when deserializing... when doing it this way the converter will get used for all enums but shouldn't pose any performance loss as it does the parsing and doesn't just test and passthrough.

    Code (csharp):
    1.  
    2. var myObj = JsonConvert.DeserializeObject<MyObjectType>(jsonString, new EnumValidationConverter());
    3.  
     

    Attached Files:

  29. Domino-Studios

    Domino-Studios

    Joined:
    Oct 26, 2012
    Posts:
    31
    Hello,

    I just purchased JSON.NET and imported it in my project. I also use PlayMaker and I have an error :
    Code (CSharp):
    1. Assets/Libraries/Playmaker/Photon Unity Networking/Editor/PhotonNetwork/AccountService.cs(181,45): error CS0433: The imported type `Newtonsoft.Json.JsonConvert' is defined multiple times
    Can you help me on this ?
     
  30. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Sure. PlayMaker must also use Json .NET for the editor. So check the editor folders. You should be able to find a Newtonsoft.Json.dll in there somewhere. Just delete that DLL and PlayMaker will also use my asset instead and everything should be happy. :)
     
  31. Domino-Studios

    Domino-Studios

    Joined:
    Oct 26, 2012
    Posts:
    31
    Perfect, thx :)
     
  32. Domino-Studios

    Domino-Studios

    Joined:
    Oct 26, 2012
    Posts:
    31
    I want to follow this.

    I have a JSON file :

    Code (JavaScript):
    1. [
    2.     {
    3.         "Id":13761640,
    4.         "Name":"Lamentation",
    5.     },
    6.     {
    7.         "Id":4542,
    8.         "Name":"Rouillette",
    9.     },
    10.     {
    11.         "Id":47653165,
    12.         "Name":"Fauchonette",
    13.     }
    14. ]
    The class
    Code (CSharp):
    1. using Wizar;
    2. using UnityEngine;
    3. using System;
    4.  
    5. namespace Wizar{
    6.     public class WeaponModel: IItem, IEquipable {
    7.    
    8.         //Private members
    9.         private int ownerId;
    10.         private string state;
    11.  
    12.         //Properties  
    13.         public int Id{get; set;}
    14.         public string Name{get; set;}
    15.         public WeaponCategory Category {get; set;}
    16.         public Type CloseTargetBehavior{get;set;}
    17.         public Type CloseZoneBehavior{get;set;}
    18.         public Type DistantTargetBehavior{get;set;}
    19.         public Type DistantZoneBehavior{get;set;}
    20.         public Vector2 GeoCoord{get;set;}
    21.         public string State{get;set;}
    22.         public int OwnerId{get;set;}
    23.     }
    24. }
    A WeaponsList class :
    Code (CSharp):
    1. using Wizar;
    2. using UnityEngine;
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6.  
    7. namespace Wizar{
    8.     public class WeaponsList
    9.     {
    10.        public List<WeaponModel> WeaponModels { get; set; }
    11.     }
    12. }
    And main class

    Code (CSharp):
    1. using Wizar;
    2. using UnityEngine;
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using Newtonsoft.Json;
    7. using System.IO;
    8.  
    9. public class LocalWorldModel: MonoBehaviour {
    10.  
    11.     //TODO : add a region radius
    12.     //private WeaponsList weaponsList;
    13.  
    14.     void Start(){
    15.    
    16.         //gen some items
    17.  
    18.         var fileName = Path.Combine(Application.streamingAssetsPath, "items.json");
    19.         StreamReader r = new StreamReader(fileName);
    20.         string json = r.ReadToEnd();
    21.  
    22.         var weaponModels = JsonConvert.DeserializeObject<WeaponsList>(json);
    23.  
    24.     }
    25.  
    26.     void Update(){
    27.     }
    28. }
    But when I hit play, I have the following error :

    Code (CSharp):
    1. JsonSerializationException: Cannot deserialize JSON array into type 'WeaponsList'.
    2. Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureArrayContract (System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract) (at Assets/Libraries/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:443)
    3. Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.Object existingValue, System.String reference) (at Assets/Libraries/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:459)
    4. Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.Object existingValue) (at Assets/Libraries/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:227)
    5. Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueNonProperty (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract) (at Assets/Libraries/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:210)
    6. Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType) (at Assets/Libraries/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:122)
    7. Newtonsoft.Json.JsonSerializer.DeserializeInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType) (at Assets/Libraries/JsonDotNet/Source/JsonSerializer.cs:424)
    8. Newtonsoft.Json.JsonSerializer.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType) (at Assets/Libraries/JsonDotNet/Source/JsonSerializer.cs:416)
    9. Newtonsoft.Json.JsonConvert.DeserializeObject (System.String value, System.Type type, Newtonsoft.Json.JsonSerializerSettings settings) (at Assets/Libraries/JsonDotNet/Source/JsonConvert.cs:755)
    10. Newtonsoft.Json.JsonConvert.DeserializeObject[WeaponsList] (System.String value, Newtonsoft.Json.JsonSerializerSettings settings) (at Assets/Libraries/JsonDotNet/Source/JsonConvert.cs:718)
    11. Newtonsoft.Json.JsonConvert.DeserializeObject[WeaponsList] (System.String value) (at Assets/Libraries/JsonDotNet/Source/JsonConvert.cs:675)
    12. LocalWorldModel.Start () (at Assets/Libraries/Wizar/LocalWorld/Models/LocalWorldModel.cs:22)
    13.  
    By the way, I manage to deserialize when there is only one element (with that in my main class)

    Code (CSharp):
    1.     WeaponModel w2 = JsonConvert.DeserializeObject<WeaponModel>(json);
    Have you got an idea on this ?
     
  33. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Your problem is exactly the opposite. Your Json just represents an array. So if you were deserializing to List<WeaponModel> or WeaponModel[] it would work fine. Your JSON will have to change if you want to do WeaponList and will need to actually look like this:

    Code (csharp):
    1.  
    2. {
    3.    "WeaponModels": [
    4.          { "Id" : 5, "Name": "Some Weapon" },
    5.          { "Id" : 6, "Name": "Some Other Weapon" }
    6.     ]
    7. }
    8.  
    Here's what I would suggest if you're having trouble getting Json to deserialize... Instead of starting with your Json construct your object first. So create a new WeaponList object, populate it with weapons... and then Serialize it and output the Json to the console or somewhere you can see it. Then you can see how that Json should be structured to properly deserialize it.
     
  34. Domino-Studios

    Domino-Studios

    Joined:
    Oct 26, 2012
    Posts:
    31
    Thx, you it works. I will follow your advice. It makes sense.
     
  35. MartinLyne

    MartinLyne

    Joined:
    Apr 25, 2013
    Posts:
    30
    I'm having some issues serializing a multidimensional array in the format of
    Code (csharp):
    1. float[,,]
    it gives me:
    Code (csharp):
    1.  
    2. NullReferenceException: Object reference not set to an instance of an object
    3. Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeMultidimensionalArray (Newtonsoft.Json.JsonWriter writer, System.Array values, Newtonsoft.Json.Serialization.JsonArrayContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContract collectionContract) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalWriter.cs:515)
    4. Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonContract valueContract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContract collectionValueContract) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalWriter.cs:151)
    5. Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalWriter.cs:72)
    6. Newtonsoft.Json.JsonSerializer.SerializeInternal (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value) (at Assets/JsonDotNet/Source/JsonSerializer.cs:454)
    7. Newtonsoft.Json.JsonSerializer.Serialize (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value) (at Assets/JsonDotNet/Source/JsonSerializer.cs:446)
    8. Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value, Formatting formatting, Newtonsoft.Json.JsonSerializerSettings settings) (at Assets/JsonDotNet/Source/JsonConvert.cs:626)
    9. Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value) (at Assets/JsonDotNet/Source/JsonConvert.cs:563)
    10.  
    I've checked the array and it has no strange values (all -1 - 1) but it is quite large, roughly 33,33,33.
    It all worked fine when the data was in jagged arrays, but that's not the ideal structure for this data.

    Any help greatly appreciated!
    M
     
  36. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Thanks for the report Martin. I'm looking into another issue with multidimensional arrays as well and it may be related. If you have Skype, could you shoot me a pm with your Skype info?
     
  37. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    This bug should be fixed now. It's being tested. If anyone else runs into the issue send me a PM and I'll get you a patch to fix. The fix will be included in the next release.
     
  38. Plattinator

    Plattinator

    Joined:
    Dec 28, 2011
    Posts:
    18
    I'm having trouble getting TypeNameHandling to work on the values inside a Dictionary<string, object>. It will apply the name handling to the dictionary itself ("$type": "System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[System.Object, mscorlib]], mscorlib"), but not to the items ("Position": {"x": 0.0,"y": 0.0,"z": -3.36}).

    I found this in the official Json.NET documentation: "JsonDictionaryAttribute has options on it to customize the JsonConverter, type name handling and reference handling that are applied to collection items." JsonDictionaryAttribute appears to be defined for WinRT, but not outside of that. I tried setting the TypeNameHandling through the JsonPropertyAttribute, but I get the same result as above. Any help would be appreciated.

    Thanks for the great library, it's working perfectly for me otherwise!
     
  39. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Hmm ill take a look and see if I can get that functionality in there. Unfortunately the WinRT stuff actually uses a newer version of Json .net. I plan to work on porting everything over to the newer v6 soon as it adds more features including async serialization and deserialization.
     
  40. Plattinator

    Plattinator

    Joined:
    Dec 28, 2011
    Posts:
    18
    Thanks, I'll work around it for now.
     
  41. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Ok, and I'm looking at the code to see if it's possible to get it working with the old version. I also have another request I'm working on to backport a feature (allowing $type to be defined anywhere, not just as the first element in the JSON for an object).
     
  42. Plattinator

    Plattinator

    Joined:
    Dec 28, 2011
    Posts:
    18
    I made a mistake on my end. I didn't notice that we were using a wrapper for Vector3 that implemented ISerializable. When I added the JsonObject attribute to it, the type serialized just fine within the dictionary. Now I'm noticing that Vector3 stores some extra data like magnitude and sqrMagnitude, even when using the provided Vector3Converter. It's not a big deal and I'm sure I could implement my own converter that only stores the x, y, and z.
     
  43. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Glad to hear it! I was trying to work out why it wouldn't be working and I thought it should be. :)

    As for the converters, you're in luck and I've already done that work for you. Look in the Extras folder that gets imported as part of the asset (JsonDotNet/Extras). There are converters for Vector2, Vector3, Vector4 and Matrix4x4 that already strip out all of the calculated properties and only serialize the relevant stuff.
     
  44. Plattinator

    Plattinator

    Joined:
    Dec 28, 2011
    Posts:
    18
    Hmm, when I don't use any converters, this is what I get

    Code (CSharp):
    1. {
    2.     "x": 0.0,
    3.     "y": 0.0,
    4.     "z": -3.36,
    5.     "normalized": {
    6.       "x": 0.0,
    7.       "y": 0.0,
    8.       "z": -1.0,
    9.       "magnitude": 1.0,
    10.       "sqrMagnitude": 1.0
    11.     },
    12.     "magnitude": 3.36,
    13.     "sqrMagnitude": 11.2895994
    14. }
    With the converter in JsonDotNet/Extras, I get this

    Code (CSharp):
    1. {
    2.   "Keys": [
    3.     "x",
    4.     "y",
    5.     "z"
    6.   ],
    7.   "x": 0.0,
    8.   "y": 0.0,
    9.   "z": -3.3599998950958252,
    10.   "normalized": {
    11.     "x": 0.0,
    12.     "y": 0.0,
    13.     "z": -1.0,
    14.     "magnitude": 1.0,
    15.     "sqrMagnitude": 1.0
    16.   },
    17.   "magnitude": 3.3599998950958252,
    18.   "sqrMagnitude": 11.289599418640137
    19. }
    It adds a set of "Keys" but still also serializes everything else.

    Edit to add:
    This is a non-issue for me right now as I decided to add the type data to our existing implementation of the ISerializable wrappers and it's working perfectly.
     
    Last edited: Sep 17, 2014
  45. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Interesting... did you put that converter on the Dictionary itself? That wouldn't work :) You'd need to pass them in as parameters to the SerializeObject overload. At any rate, glad it's working for you!
     
  46. Plattinator

    Plattinator

    Joined:
    Dec 28, 2011
    Posts:
    18
    Right, I passed it as part of the JsonSerializerSettings. Anyhow, thanks for the support, your customer care is fantastic!
     
  47. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Thanks! Appreciate the kind words!
     
  48. Domino-Studios

    Domino-Studios

    Joined:
    Oct 26, 2012
    Posts:
    31
    Hello,

    now, I would like to replace my Listby a Dictionary. But I am stuck on deserialize it.

    I have a base class
    Code (CSharp):
    1. using Wizar;
    2. using UnityEngine;
    3. using System;
    4.  
    5. namespace Wizar{
    6.     public class Item{
    7.         public int Id {get;set;}
    8.         public Vector2 GeoCoord{get;set;}
    9.         public int OwnerId{get;set;}
    10.         public string State{get;set;}
    11.         public string Name{get;set;}
    12.         public Type Type{get;set;}
    13.     }
    14. }
    and some derived class

    Code (CSharp):
    1. using Wizar;
    2. using UnityEngine;
    3. using System;
    4.  
    5. namespace Wizar{
    6.  
    7.     public class WeaponModel: Item, IEquipable {
    8.  
    9.         //Properties      
    10.         public WeaponCategory Category {get; set;}
    11.         public Type CloseTargetBehavior{get;set;}
    12.         public Type CloseZoneBehavior{get;set;}
    13.         public Type DistantTargetBehavior{get;set;}
    14.         public Type DistantZoneBehavior{get;set;}
    15.  
    16.     }
    17.     public class MascotModel: Item, IOwnable {
    18.      
    19.           //Properties      
    20.         public MascotCategory Category {get; set;}
    21.  
    22.     }
    23.  
    24.     public class ConsumableModel: Item {
    25.  
    26.         //Properties      
    27.         public float Price {get; set;}
    28.      
    29.     }
    30. }
    I create some weapons, mascots, consumables...

    Code (CSharp):
    1.  
    2. WeaponModel w1 = new WeaponModel();
    3. MascotModel m1 = new MascotModel();
    4. ...
    5.  
    I put them in a class which wrap a dictionary (as you adviced)
    Code (CSharp):
    1.  
    2.  
    3. namespace Wizar{
    4.     public class ItemsCollection {
    5.         public Dictionary<int, Item> Items {get;set;}
    6.  
    7.         public ItemsCollection(){
    8.             Items = new Dictionary<int, Item>();
    9.         }
    10.     }
    11. }
    12.  
    13. GlobalItemsCollection.Items.Add(45451, w1);
    14. GlobalItemsCollection.Items.Add(45415, m1);
    15.  
    16.  
    17. ...
    18.  
    I serialized this and all works fine.
    Code (CSharp):
    1. {
    2.     "45451": {
    3.          "Id":45451,
    4.          "Type":"Wizar.WeaponModel",
    5.         "Name":"Lamentation",
    6.         "Category":3,
    7.         "CloseTargetBehavior":"Wizar.Circular",
    8.         "CloseZoneBehavior":"Wizar.MeleeCircle",
    9.         "DistantTargetBehavior":"Wizar.LaunchOnce",
    10.         "DistantZoneBehavior":"Wizar.LaunchIntoCrowd",
    11.         "GeoCoord":{
    12.             "x":47.9375,
    13.             "y":-2.39894
    14.         },
    15.         "State":null,
    16.         "OwnerId":1
    17.     },
    18.     "45": {
    19.         "Id":45415,
    20.         "Type":"Wizar.MascotModel",
    21.         "Name":"Poku",
    22.         "Category":1,
    23.         "GeoCoord":{
    24.             "x":47.9375,
    25.             "y":-2.39894
    26.         },
    27.         "State":null,
    28.         "OwnerId":1
    29.     },
    30.     "549465": {
    31.         "Id": 549465,
    32.         "Type":"Wizar.ConsumableModel",
    33.         "Name": "Radis",
    34.         "Category": 0,
    35.         "GeoCoord": {
    36.             "x":47.93759,
    37.             "y":-2.39896
    38.         },
    39.         "State": null,
    40.         "OwnerId": 1
    41.     }
    42. }
    But I can't deserialized that because the parser wants to cast an Item, not its subclass (WeaponModel, MascotModel, ConsumableModel) ...

    So in short, how you can deserialize a dictionary where the values are some derived object ? I think it is more an architectural problem, but any help would be appreciated on this :)
     
  49. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Code (csharp):
    1.  
    2. var settings = new JsonSerializerSettings();
    3. settings.TypeNameHandlng = TypeNameHandling.All;
    4. var json = JsonConvert.SerializeObject(yourObj, Formatting.None, settings);
    5.  
     
  50. Domino-Studios

    Domino-Studios

    Joined:
    Oct 26, 2012
    Posts:
    31
    #IDontKnowWhatIAmDoing but it works :)

    Thx :)