Search Unity

JSON .NET for Unity

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

  1. AdamGoodrich

    AdamGoodrich

    Joined:
    Feb 12, 2013
    Posts:
    3,783
    Anyone had any luck with Texture2D?

    I am unable to import a class that I just exported:

    JsonSerializationException: Unable to find a constructor to use for type UnityEngine.Texture2D. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateAndPopulateObject (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, System.String id) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:818)
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, System.Object existingValue) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:407)
    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/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:225)
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueProperty (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonProperty property, System.Object target, Boolean gottenCurrentValue, System.Object currentValue) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:200)
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.SetPropertyValue (Newtonsoft.Json.Serialization.JsonProperty property, Newtonsoft.Json.JsonReader reader, System.Object target) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:564)
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject (System.Object newObject, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, System.String id) (at Assets/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:1090)
     
  2. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I'll have to take a look... since Texture2D doesn't have an empty constructor that's accessible the deserializer can't create an instance of it. What platform is this or is it any platform? Most likely you're going to have to create a proxy object (like a struct with properties that match Texture2D) and then deserialize to the proxy, then create your Texture2D from that. Since this is a property of an object, you can control the serialization with attributes so you'll want to create a custom value binder for Texture2D that does what I described above and then set it with the proper attribute.
     
  3. AdamGoodrich

    AdamGoodrich

    Joined:
    Feb 12, 2013
    Posts:
    3,783
    Hi Dustin, thanks for your response.

    Yeap this is any platform - currently developing on Mac and decided to see if I could use your asset. Nice work btw - super easy to get up and running and so handy! Going to use this for all my serialisation / deserialisation from now on :)

    Figured I would need to make an intermediary. Was just hoping that I wouldn't have to. I populate a fairly complex structure in the editor, and being able to drop textures into the appropriate field and then export / import them is pretty handy.

    When the texture has been assigned, the system drops them out no probs, if assigned 'none' then it throws an exception. The former is easily handled, its getting them back in thats the bigger problem.

    What I want to do is leave the public texture field as is because it makes editing a breeze, then either dynamically detect that object type and manually serialise / deserialise it with a type specific plugin (custom value binder??), or mark just that field as exempt from serialisation.

    Do you have an example of a custom value binder?

    Thanks,
    Adam.
     
    Last edited: Dec 27, 2013
  4. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
  5. AdamGoodrich

    AdamGoodrich

    Joined:
    Feb 12, 2013
    Posts:
    3,783
    Hi Dustin,

    Ok, got to next issue.

    I wrote a custom resolver and converter, and can export the json file no problems.

    Because my textures are reference to a file, i decided to move my texture to the a Resources/Textures directory, and then load the resource by name.

    So the texture when exported looks like this:

    "texture":newTexture2D(
    "rock_mud_09_color"
    ),

    However when I go to import it again I get the following error - and based on debug logging its not even making it into my import routine:

    JsonReaderException: Unexpected character while parsing constructor: 2. Line 7, position 29.
    Newtonsoft.Json.JsonTextReader.ParseConstructor () (at Assets/Resources/Scripts/JsonDotNet/Source/JsonTextReader.cs:757)
    Newtonsoft.Json.JsonTextReader.ParseValue (Char currentChar) (at Assets/Resources/Scripts/JsonDotNet/Source/JsonTextReader.cs:653)
    Newtonsoft.Json.JsonTextReader.ReadInternal () (at Assets/Resources/Scripts/JsonDotNet/Source/JsonTextReader.cs:459)
    Newtonsoft.Json.JsonTextReader.Read () (at Assets/Resources/Scripts/JsonDotNet/Source/JsonTextReader.cs:322)
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType (Newtonsoft.Json.JsonReader reader, System.Type t, Newtonsoft.Json.JsonConverter propertyConverter) (at Assets/Resources/Scripts/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:1024)
    Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject (System.Object newObject, Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, System.String id) (at Assets/Resources/Scripts/JsonDotNet/Source/Serialization/JsonSerializerInternalReader.cs:1085)

    I have attached my converter and contract resolver.

    Here is the code that calls them:

    ///<summary>
    ///ExportsthetextureSettoaJsonfileintheAssets/Jsondirectory, withthenametextureSet.name + '.json'
    ///</summary>
    private void ExportJSON() {

    //Get the data path
    string dataPath = System.IO.Path.Combine(Application.dataPath, "Resources");
    dataPath = System.IO.Path.Combine(dataPath, "Json");
    dataPath = System.IO.Path.Combine(dataPath, textureSet.name + ".json");

    //Create the serializer and serialise the textureset
    JsonSerializer serializer = new JsonSerializer();
    serializer.NullValueHandling = NullValueHandling.Ignore;
    serializer.DefaultValueHandling = DefaultValueHandling.Ignore;
    serializer.ContractResolver = new JsonTexture2DContractResolver();

    using (System.IO.StreamWriter sw = new System.IO.StreamWriter(dataPath))
    {
    using (JsonWriter writer = new JsonTextWriter(sw))
    {
    writer.Formatting = Formatting.Indented;
    serializer.Serialize(writer, textureSet);
    }
    }

    //Let the debug log know about it
    Debug.Log("Wrote: " + dataPath);
    }

    private void ImportJSON() {

    //Our new texture set
    TextureSet ts;

    //Get the data path
    string dataPath = System.IO.Path.Combine(Application.dataPath, "Resources");
    dataPath = System.IO.Path.Combine(dataPath, "Json");
    dataPath = System.IO.Path.Combine(dataPath, textureSet.name + ".json");

    //Create the serializer and serialise the textureset
    JsonSerializer serializer = new JsonSerializer();
    serializer.NullValueHandling = NullValueHandling.Ignore;
    serializer.DefaultValueHandling = DefaultValueHandling.Ignore;
    serializer.ContractResolver = new JsonTexture2DContractResolver();

    using (System.IO.StreamReader sr = System.IO.File.OpenText(dataPath))
    {
    ts = (TextureSet) serializer.Deserialize(sr, typeof(TextureSet));
    }

    //Let the debug log know about it
    Debug.Log("Read: " + dataPath);
    }


    Your help is much appreciated.

    Cheers,
    Adam.
     

    Attached Files:

    Last edited: Dec 30, 2013
  6. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Hmm... this doesn't look like valid Json... it looks like what you're trying to do is pass that string into the constructor? You might be better off as we discussed before... deserializing to a proxy class. So let's say it's Texture2DProxy. Then you Deserialize it to your Texture2DProxy (which can be a struct to avoid allocations on the heap). Then return your Texture2D like this:

    Code (csharp):
    1.  
    2. var returnValue = new Texture2D(deserializedProxy.name);
    3.  
    Does that make sense?

    Or... if Texture2D isn't a sealed class (not sure if it is), you can create a proxy like this:

    Code (csharp):
    1.  
    2. public class Texture2DProxy : Texture2D
    3. {
    4.    public Texture2DProxy() {}
    5. }
    6.  
    Then same steps as above... but since Texture2DProxy now has a public parameterless constructor it should deserialize fine... then use the "name" property of it to create your new Texture2D instance. This would be the simplest because you don't have to duplicate any of the properties. However, if you want to go for efficiency and avoid the heap allocations I would go the struct route and replicate Texture2D with it.

    Edit: If you're handling the above JSON I also noticed something... if you really do what to generate JSON like you used above you'll need to fix the quotes:

    "texture":"newTexture2D(
    \"rock_mud_09_color\"
    )"
     
    Last edited: Dec 30, 2013
  7. AdamGoodrich

    AdamGoodrich

    Joined:
    Feb 12, 2013
    Posts:
    3,783
    Hi Dustin,

    You got in too quick - i added a bunch of code to demonstrate in more detail what I am doing.

    I based my code off the date code in your source directories.

    Can you take a quick look.

    Ta,
    Adam.
     
  8. AdamGoodrich

    AdamGoodrich

    Joined:
    Feb 12, 2013
    Posts:
    3,783
    Also, the JSON code that I pasted there was generated programatically by this:

    writer.WriteStartConstructor("Texture2D");
    writer.WriteValue(texture.name);
    writer.WriteEndConstructor();


    I added the constructor stuff as it did not recognise the type when i removed it.
     
  9. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Ok... give me a little time to look at it and I'll see if I can get it figured out for you.
     
  10. altheonix

    altheonix

    Joined:
    Oct 20, 2012
    Posts:
    19
    Hello,

    Is there a way to not serialize magnitude and sqrmagnitude for vector2 ?

    the result is this
    "Offset":{"x":0.0,"y":0.0,"magnitude":0.0,"sqrMagnitude":0.0}

    what I want is like this
    "Offset":{"x":0.0,"y":0.0}

    Its not very important but just curious if there's a way to do that.
    Its more convenient to see the variable that I only need.
    thanks. :D
     
  11. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Yep... there are a few ways. With your own classes you can use attributes to prevent specific properties from serializing by specifying it as OptIn and then marking the fields you want serialized, or use the JsonIgnore attribute to ignore specific members. With built in classes there area couple of methods.

    What you probably want to look at is using a custom ContractResolver. Take a look at this bit of documentation:
    http://james.newtonking.com/json/help/?topic=html/ReducingSerializedJSONSize.htm

    If you go down to the IContractResolver section, there is an example that shows how to only serialize properties that start with the letter "A". In your case you would just serialize specific members based on the type, so for Vector2 for instance, you would just serialize the "x" and "y" properties.
     
  12. andymads

    andymads

    Joined:
    Jun 16, 2011
    Posts:
    1,614
    @Dustin, a quick question. Does your system allow for commenting JSON in any way? One thing I like about XML is the block commenting.
     
  13. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
  14. andymads

    andymads

    Joined:
    Jun 16, 2011
    Posts:
    1,614
    Sorry, I meant commenting manually like you would line/block comment code to quickly ignore it (but you don't want to remove it).
     
    Last edited: Jan 7, 2014
  15. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    No, that's not supported directly. You could accomplish it by creating a custom converter attribute and use it to write your properties as comments though.
     
  16. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Just a fun nugget for everyone here. I worked with Adam to serialize Texture2D and properly Deserialize it. There are lots of ways you can go about doing it by using a custom JsonConverter. We created a Texture2DConverter that works for his use case where his Textures are located in the Resources/Textures folder so he can use Resources.Load. Of course, this can be modified to work any number of ways... you could even write out your own properties and store the byte array of the texture so you can load it back up later.

    In this case, we only serialized the "name" property of the Texture2D. Then we deserialized to a proxy struct (Texture2DProxy) and used the name to dynamically load and return a Texture2D for deserialization. This is just an example of how you can use custom converters to massage your json and objects.

    You wouldn't even need to use the proxy below and could just read the name in as a string... the benefit of the proxy is that later you could do:

    Code (csharp):
    1.  
    2.  
    3. var proxy = JsonConvert.DeserializeObject<Texture2DProxy>(serializedJson);
    4.  
    5.  
    The above would take your serialized Texture2D and deserialize it as the proxy type with only the "name" property so you could load it back in later.

    To use this converter you could serialize like this:

    Code (csharp):
    1.  
    2. var serialized = JsonConvert.SerializeObject(myTex2D, new Texture2DConverter());
    3.  
    4. //and
    5.  
    6. var newTex2D = JsonConvert.DeserializeObject<Texture2D>(myTex2D, new Texture2DConverter());
    7.  
    8.  
    Of course you could skip the converter for serialization so you serialize everything (for reference) and just use it when deserializing. Or, let's say you have a class with a Texture2D property... you can specify the converter to only be used for that property as follows:

    Code (csharp):
    1.  
    2. public class MySuperSpecialClass
    3. {
    4.      [JsonConverter(typeof(Texture2DConverter))]
    5.      public Texture2D MyTexture { get; set; }
    6. }
    7.  

    And here is an example of the actual converter:


    Code (csharp):
    1.  
    2. using System;
    3. using System.Globalization;
    4. using Newtonsoft.Json.Utilities;
    5. using UnityEngine;
    6.  
    7. namespace Newtonsoft.Json.Converters
    8. {
    9.     /// <summary>
    10.     /// Provides a base class for converting a <see cref="Texture2D"/> to and from JSON.
    11.     /// </summary>
    12.     public class Texture2DConverter : JsonConverter
    13.     {
    14.         /// <summary>
    15.         /// Determines whether this instance can convert the specified object type.
    16.         /// </summary>
    17.         /// <param name="objectType">Type of the object.</param>
    18.         /// <returns>
    19.         ///     <c>true</c> if this instance can convert the specified object type; otherwise, <c>false</c>.
    20.         /// </returns>
    21.         public override bool CanConvert(Type objectType)
    22.         {
    23.             if (objectType == typeof(Texture2D))
    24.                 return true;
    25.            
    26.             return false;
    27.         }
    28.  
    29.         /// <summary>
    30.         /// Writes the JSON representation of the object.
    31.         /// </summary>
    32.         /// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
    33.         /// <param name="value">The value.</param>
    34.         /// <param name="serializer">The calling serializer.</param>
    35.         public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    36.         {
    37.             Texture2D texture;
    38.  
    39.             if (value is Texture2D)
    40.             {
    41.                 texture = (Texture2D)value;
    42.             }
    43.             else
    44.             {
    45.                 throw new Exception("Expected Texture2D object value.");
    46.             }
    47.            
    48.             writer.WriteStartObject();
    49.             writer.WritePropertyName("name");
    50.             writer.WriteValue(texture.name);
    51.             writer.WriteEndObject();
    52.            
    53.         }
    54.        
    55.         /// <summary>
    56.         /// Reads the JSON representation of the object.
    57.         /// </summary>
    58.         /// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
    59.         /// <param name="objectType">Type of the object.</param>
    60.         /// <param name="existingValue">The existing property value of the JSON that is being converted.</param>
    61.         /// <param name="serializer">The calling serializer.</param>
    62.         /// <returns>The object value.</returns>
    63.         public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    64.         {
    65.             Debug.Log ("Reading Texture2D");
    66.  
    67.             if (reader.TokenType == JsonToken.Null)
    68.             {
    69.                 if (!ReflectionUtils.IsNullableType(objectType))
    70.                     throw new Exception("Cannot convert null value to {0}.".FormatWith(CultureInfo.InvariantCulture, objectType));
    71.                 return null;
    72.             }
    73.  
    74.  
    75.             var proxy = new Texture2DProxy();
    76.  
    77.             while (reader.Read())
    78.             {
    79.                 if (reader.TokenType == JsonToken.PropertyName)
    80.                 {
    81.                     //convert the property to lower case
    82.                     var readerValue = reader.Value.ToString().ToLower();
    83.                     if (readerValue == "name"  reader.Read())
    84.                     {
    85.                         proxy.name = reader.Value as string;
    86.                     }
    87.                 }
    88.             }
    89.  
    90.             Debug.Log("Loading " + "Textures/" + proxy.name);
    91.  
    92.             Texture2D texture; //Hack to stop unassigned error
    93.             if (proxy.name.Length > 0) {
    94.                 texture =  Resources.Load("Textures/" + proxy.name, typeof(Texture2D)) as Texture2D;
    95.             }
    96.             else {
    97.                 texture = new Texture2D(8, 8) {name = "Broken Texture"};
    98.             }
    99.  
    100.             return texture;
    101.         }
    102.  
    103.     }
    104.  
    105.     public struct Texture2DProxy
    106.     {
    107.         public string name { get; set; }
    108.     }
    109. }
    110.  
     
    Last edited: Jan 7, 2014
  17. AdamGoodrich

    AdamGoodrich

    Joined:
    Feb 12, 2013
    Posts:
    3,783
    Many thanks to Dustin for his help!!! :)
     
  18. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    JSON .NET for Unity is now only $20!

    Serialization is integral to persisting data. This community has been extremely supportive of my asset and I wanted to return the favor by making sure it is affordable for everyone, so the price has been reduced on both FastSpring and the Asset Store.
     
  19. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    For new readers of this thread, the previous price was $45. :)
     
  20. Zenix

    Zenix

    Joined:
    Nov 9, 2009
    Posts:
    213
    Just purchased this and integrated it into my game, but getting JIT errors straight away on iOS.

     
  21. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Hmm... looks like that's happening in the Constructor for CollectionWrapper. Which version of iOS and Device are you using? Which version of Unity? Could you provide me with a quick Repro as well as send me a private message with your Skype info and we can troubleshoot it?
     
  22. Zenix

    Zenix

    Joined:
    Nov 9, 2009
    Posts:
    213
    Having the issue on the iPad 2, iPad Mini, iPad 4. iOS versions 6.0.2, and 7. Unity version 4.2.0.

    Will narrow down a simple repro.
    (Trying to replace the current Json parser in a fairly large project, so it's not that straight forward to isolate the issue.)
     
  23. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I may be able to help you narrow it down. Looking at where the error is occurring... it is trying to cast an object to a collection. It looks like a case where it's not identifying the collection type and attempting to just cast to ICollection<T>. Generic typed interfaces don't play well with AOT. My guess is that you have your own collection type that implements ICollection<T>. If you could identify the class / property that's failing I could jump on Skype with you and come up with a fix once we're sure what's causing the issue.

    Thanks,

    Dustin
     
  24. Zenix

    Zenix

    Joined:
    Nov 9, 2009
    Posts:
    213
    Trying to narrow it down on my end, I have isolated a chunk of code that causes the issue. I can't post it unfortunately as it's company code, but I can say that the only collections it uses are Dictionary<T1,T2>, HashSet<T>, and List<T>.

    I use a custom converter to deserialize my object, as it contains nested objects and collections, as described on this page:
    http://stackoverflow.com/questions/6416017/json-net-deserializing-nested-dictionaries
     
  25. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I think the problem is the HashSet<T>. This is going to be a tough one to work around... Looking at the implementation, HashSet<T> has ICollection<T> as a base. In fact, it pretty much shares the same base structure as List<T> except it doesn't implement IList<T>.

    The inheritance chain of HashSet<T> throws up a big red flag though:
    ICollection<T>, IEnumerable<T>, Enumerable, ISerializable, IDeserializationCallback

    In .NET 4 and above it also implements a new interface called ISet<T> making it really easy to identify a hashset based on the inheritance chain... unfortunately, in .NET 3.5 it does not have that interface... in fact ISet<T> doesn't exist in .NET 3.5. The only thing that really sets it apart from other collections is that it is marked ISerializable, however I can't check for that interface becauase it would incorrectly detect custom collections that implement ISerializable. Also, that interface is unavailable in WinRT so it would break for Windows Store Apps and Windows Phone 8.

    So, I'm going to have to dig through the code and see if I can detect HashSet<T> and do the casting appropriately. On all other platforms it should work just fine, but since it's an unknown collection type it falls back to trying a cast to ICollection<T> (in your case looks to be ICollection<int>) which blows up AOT since AOT compilation breaks when trying to cast to generic interfaces.
     
  26. Zenix

    Zenix

    Joined:
    Nov 9, 2009
    Posts:
    213
    I appreciate you looking into this for me.

    Having a quick look at our code, we don't use HashSet very much on client side, so it's that's the one causing the issues I may be able to replace our usages of it with something else.


    Edit: I just replaced the HashSet with a List in my test code, and now I get the following exception:

     
    Last edited: Jan 20, 2014
  27. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I'm 100% positive HashSet is an issue... I'm not sure why you'd be getting an issue with a Dictionary though... Out of curiosity.. if you run the Serialization tests from the test scene that came with the Asset, are you getting any errors?
     
  28. alan-lawrance

    alan-lawrance

    Joined:
    Feb 1, 2013
    Posts:
    360
    Hi Dustin --

    Just tried importing into Unity 4.3.2f1 (Windows version) and I'm seeing errors like the following:

    Assets/JsonDotNet/Examples/Tests/JsonTestScript.cs(108,22): error CS1502: The best overloaded method match for `System.Collections.Generic.List<SampleBase>.Add(SampleBase)' has some invalid arguments

    Assets/JsonDotNet/Examples/Tests/JsonTestScript.cs(115,31): error CS1061: Type `SampleBase' does not contain a definition for `TextValue' and no extension method `TextValue' of type `SampleBase' could be found (are you missing a using directive or an assembly reference?)

    I checked to make sure I had the latest version from the Asset Store, and it said I'm up to date.

    The errors are all in JsonTestScript.cs, so I could just remove that for now, but I'm curious if this is known and if there is a fix/patch planned for this.
     
  29. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Are you sure you imported everything? I just imported from the asset store into a new project and didn't get any errors...

    In the:
    JsonDotNet/Examples/Tests/TestModels folder you should have a file called SampleBase.cs. It just looks like this:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. namespace Assets.DustinHorne.JsonDotNetUnity.TestCases.TestModels
    5. {
    6.     public class SampleBase
    7.     {
    8.         public string TextValue { get; set; }
    9.         public int NumberValue { get; set; }
    10.         public Vector3 VectorValue { get; set; }
    11.     }
    12. }
    13.  
    As for the first error... it looks like there is an errant space so it says "S ampleBase" instead of "SampleBase". But looking at it... The line in question, line 108, actually reads:

    Code (csharp):
    1.  
    2. list.Add(TestCaseUtils.GetSampleChid());
    3.  
    Are you sure you're importing the latest version for the asset store as I'm not seeing any of those issues..
     
  30. alan-lawrance

    alan-lawrance

    Joined:
    Feb 1, 2013
    Posts:
    360
    It appears that FingerGestures (from Asset Store) is using a SampleBase class as well -- so there is a conflict there. Looks like I just need to rename one of them.
     
  31. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Or just add this at the top of the Test script file:

    Code (csharp):
    1.  
    2. using SampleBase = Assets.DustinHorne.JsonDotNetUnity.TestCases.TestModels.SampleBase;
    3.  
    That will make the error go away. I'll update that for future versions to make sure I'm fully qualifying in my test scripts.
     
  32. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    @Zenix -

    I think I may have a fix for the Dictionary issue. The problem is that the AOT compiler can't find the appropriate methods to construct the dictionary (or more appropriately the IEqualityComparer<T> that it uses). I'm guessing that you're not instantiating that dictionary type from scratch anywhere in the code, or at least not that the AOT compiler has found yet. This makes it impossible to construct the dictionary via reflection.

    However, you can construct that dictionary in your class constructor. So let's say it's a property called MyValues and your class looks like this:

    Code (csharp):
    1.  
    2. public class MyClassObject
    3. {
    4.       public Dictionary<string, byte> MyValues { get; set; }
    5. }
    6.  
    By default, MyValues is null and the AOT compiler hasn't compiled any code to construct it yet so that constructor can't be executed via reflection. However, if you construct an empty Dictionary in your constructor:

    Code (csharp):
    1.  
    2. public class MyClassObject
    3. {
    4.        public Dictionary<string, byte> MyValues { get; set; }
    5.  
    6.        public MyClassObject()
    7.        {
    8.                MyValues = new Dictionary<string, byte>();
    9.        }
    10. }
    11.  
    Now it should be able to deserialize it just fine because that constructor code exists and the EqualityComparer constructor code exists internally so the serializer can invoke the constructor method without a problem.

    If you don't want to initialize that property automatically because you're checking for null, you can just initialize a dummy one in your constructor, i.e.:

    Code (csharp):
    1.  
    2. var tempDictionary = new Dictionary<string, byte>();
    3.  
    Then just let it fall away, but it will generate a little more garbage whenever that class gets instantiated. Or, if you know what all of your dictionary types are, you can just instantiate them all up front when your game loads.

    I believe this is also what's causing the problem with HashSet<T> because it also uses an equality comparer though I'm not positive yet.
     
  33. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Zenix -

    Have you had a chance to try it after instantiating your Dictionary?
     
  34. sloopidoopi

    sloopidoopi

    Joined:
    Jan 2, 2010
    Posts:
    244
    Hi,
    first of all I want to say thank you for this great Asset and the great support!
    I make my first steps into all this JSON serialization and I realize that this is not so easy for JSON.NET newbies like I thought. As you are an expert it would be fine if you could provide some links to good tutorials or provide more info on your site. Perhaps a forum would be great as it's not fun to read all the information from this thread.(And it's getting longer and longer).
    My problem for example was that I wanted to serialze an object with some private field to a file on disc. It was a pain to get all the information from google. The infos from http://james.newtonking.com/json/help/index.html are more like a reference for people who know all the tiny things you have to consider.
    It would be great to have a examples that stores/retrieves data to/from the filesystem with an object that has different serialization attributes , fields, properties, arrays.... .
     
  35. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Hey sloopidoopi, thanks for the feedback. I'm actually working on creating some offline documentation since they're now requiring it for asset store submissions and I'll be including it in my next update. You're right that the original author's site is more like a reference and it does make it difficult sometimes to find good examples. I've always had better luck using blogs or stackoverflow.

    If you do have any specific questions on how to do something, don't hesitate to reach out to me. Send me a PM or shoot me an email (my email address is in the readme.txt file that ships with the asset). Once I get some better offline documentation and examples I intend to publish more online examples as well. I've had several requests for how to do different things and it's important for me to get those requests because I start to see what features people are using the most and what are most important. That will help me to provide better documentation.
     
  36. Zenix

    Zenix

    Joined:
    Nov 9, 2009
    Posts:
    213
    Hey,

    Yeah, I replaced the Hashset and pre-instantiated the dictionary, and that got that request working correctly.

    The serializing code however, fails all the time. Any time I try and serialize an array, I get the dreaded "System.String doesn't implement interface System.Collections.IEnumerator" crash, due to your usage of foreach.

    So we're replacing the troubled areas with our own serialization/deserialization code that doesn't use any JIT or Foreach.
     
  37. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Can you tell me where that is erroring out? It must be hitting somewhere I didn't replace. If you look, there's an AOT folder which has an IEnumerable extension for an AOT safe ForEach loop. So in your IEnumerable you just call

    Code (csharp):
    1.  
    2. enumerableValue.ForEach(itm => () {
    3.      //function here
    4. });
    5.  
    You should be able to find a bunch of other places in the code I implemented that. It only gets included and implemented when the target framework is UNITY_IOS. If you can tell me where it's hitting the enumerable error I'll go in and get it fixed up and I can send you the updated code.
     
  38. Zenix

    Zenix

    Joined:
    Nov 9, 2009
    Posts:
    213
    I believe it's line 426 of JsonSerializerInternalWriter.cs.

    I did a search for the ForEach extension method, and only found 4 usages of it, none of them in JsonSerializerInternalWriter (which does have 3 usages of the normal foreach).
     
  39. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Alright I'll take a look. I haven't replaced them all because not all of the code is actually reached on an iOS device and some of those loops were on internal enumerables which I had yet to see that exception fire on. I think the best bet would be for me to replace all ForEach loops on iOS with the AOT safe method.
     
  40. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Just a heads up for everyone. Something may have changed with Unity 4.3.3 that broke some serialization for Windows Phone 8. After an upgrade to 4.3.3 even the serialization tests fail with a "Missing Method Exception" when trying to serialize a simple Vector3. I am looking into the issue.
     
  41. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    I've just confirmed that this is only happening on the physical Windows Phone device. I suspect it has to do with some of the missing framework classes that the Unity team shimmed back in for 4.3.3.
     
  42. Ben-BearFish

    Ben-BearFish

    Joined:
    Sep 6, 2011
    Posts:
    1,204
    Currently we have your plugin running, and it's great. We can Serialize our data, then Deserialize it when needed.

    In our game we have dialogue, and other startup data that we would like to have in our Assets folder as a text file that we can load from, so that our designers can write the dialogue and data from that file without having to deal with code.

    I was wondering is it possible to do that with your plugin? Does the text file need to be in JSON format, and if so what's the correct format to setup the text JSon file so that it can be properly deserialized? Thank you.
     
  43. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Ben -

    I'm not sure if I completely understand what you're asking for. There are two formats supported by the plugin. You can do Json or Bson. Bson is a binary format so your serialized objects aren't in plain text. As for dialogue, what format it needs to be in depends on how you're accessing it in your game. The Json just needs to match the format of the classes you're using to load the data.

    If what you're looking for is a way for your designers to be able to create the files, I could probably help you or at least point you in the write direction to create a simple web or winforms app that would generate and manage the files for you.
     
  44. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Update: So, while adding missing .NET types in WinRTLegacy.dll, the Unity team has broken some basic .NET functionality when deploying to a Windows Phone device. According to a post, it looks like they have no intention of fixing it any time soon because there is a "workaround". Unfortunately, the workaround involves replacing the WinRTLegacy.dll in Unity 4.3.3 with the one in 4.3.2 (which also means you lose those added .NET classes).

    At any rate, if you need to have this working with Unity 4.3.3 and Windows Phone 8, here is the thread with details on the workaround:
    http://forum.unity3d.com/threads/223065-Unity-4-3-3-Type-GetMembers(BindingFlags)-crash
     
  45. altheonix

    altheonix

    Joined:
    Oct 20, 2012
    Posts:
    19
    Im sorry i can't understand this :sad: , would you mind to give me some example about contract resolver?
     
  46. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Altheonix -

    I think the easiest thing for you would be to just use a JsonConverter for it. Look at this post:
    http://forum.unity3d.com/threads/200336-RELEASED-JSON-NET-For-Unity-3-5-with-AOT-Support?p=1476157&viewfull=1#post1476157

    That shows how we selectively serialized and deserialized bits of a Texture2D. In your case you would create the converter the same way and apply it to your Vector3 properties.

    The difference is... where we just wrote the "name" property and value... you'll write the "x", "y" and "z" properties and values and ignore the rest. For deserialization you'll just construct a Vector3, set those values and return it.
     
  47. MyoungSu-Go

    MyoungSu-Go

    Joined:
    Feb 3, 2014
    Posts:
    1
    Thanks for your efforts.

    I bought your Json.Net for Unity. I'm trying to apply it to my projects(actually network system).
    But I have a problem. My other projects (like server-side) should not import Unity3D library(DLL).

    I hope to use only one json library.
    How should I do?
     
  48. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    @Everyone: I've confirmed that the Type.GetTypeCode issue has been fixed within Unity and the next 4.3.x version will address the issue.

    @MyoungSu:

    Is your backend server a Windows Server? If it is and your backend site is written in .NET, just pull the Newtonsoft JSON .NET library from NuGet since this is a port of that library. You can use that in your server side and it will work just fine. If you're using something else (i.e. LAMP stack), then there is most likely a JSON parsing library for it. What is your backend written in?
     
  49. BrUnO-XaVIeR

    BrUnO-XaVIeR

    Joined:
    Dec 6, 2010
    Posts:
    1,687
    Do your library have the DataContractJsonSerializer methods?
    Would be great to have it in Unity.
     
  50. Dustin-Horne

    Dustin-Horne

    Joined:
    Apr 4, 2013
    Posts:
    4,568
    Which methods are those? Unity doesn't have anything in the System.Data namespace, however I did add the DataMember, DataContract, and EnumMember attributes back in straight from the Mono source so it does have support for classes you may share with a WCF service implementation. What specifically are you looking for?