Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

JsonSerializationException: Self referencing loop detected

Discussion in 'Scripting' started by Bennyman, Apr 7, 2022.

  1. Bennyman

    Bennyman

    Joined:
    Feb 9, 2016
    Posts:
    13
    Hello,

    I 'm using the Newtonsoft.json to make some saving loading function.
    So far it was working, now I get this error :

    JsonSerializationException: Self referencing loop detected for property 'normalized' with type 'UnityEngine.Vector3'. Path 'systemSimulationTransform_Pos.normalized'.



    Here is the detailed error :

    JsonSerializationException: Self referencing loop detected for property 'normalized' with type 'UnityEngine.Vector3'. Path 'systemSimulationTransform_Pos.normalized'.
    Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonProperty property, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonContainerContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonProperty property, Newtonsoft.Json.Serialization.JsonContract& memberContract, System.Object& memberValue) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract collectionContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    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.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract collectionContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    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.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject (Newtonsoft.Json.JsonWriter writer, System.Object value, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract collectionContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    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.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerProperty) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.JsonSerializer.SerializeInternal (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.JsonSerializer.Serialize (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.JsonConvert.SerializeObjectInternal (System.Object value, System.Type type, Newtonsoft.Json.JsonSerializer jsonSerializer) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value, System.Type type, Newtonsoft.Json.Formatting formatting, Newtonsoft.Json.JsonSerializerSettings settings) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value, Newtonsoft.Json.Formatting formatting, Newtonsoft.Json.JsonSerializerSettings settings) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value, Newtonsoft.Json.Formatting formatting) (at <bc3985d37b0241b48fc21474b2de25bd>:0)
    ImportExportJSONManager._createSaveJSON () (at Assets/Scripts/Json/ImportExportJSONManager.cs:393)
    ImportExportJSONManager.Save () (at Assets/Scripts/Json/ImportExportJSONManager.cs:121)
    ImportExportJSONManagerEditor.OnInspectorGUI () (at Assets/Editor/ImportExportJSONManagerEditor.cs:42)
    UnityEditor.UIElements.InspectorElement+<>c__DisplayClass59_0.<CreateIMGUIInspectorFromEditor>b__0 () (at <5cd53c58cab44054a1ac592b0da25132>:0)
    UnityEngine.GUIUtility:processEvent(Int32, IntPtr, Boolean&)


    Here is the code that cause the error:
    Code (CSharp):
    1. return JsonConvert.SerializeObject(templateClass,Formatting.Indented);
    I search on internet, and found that some options can be added to prevent this kind of error but I don't know how to/where implement them.

    Could you help me?

    Thanks
    Ben
     
  2. ensiferum888

    ensiferum888

    Joined:
    May 11, 2013
    Posts:
    317
    NewtonSoft has a hard time serializing structs (Vector3 is defined as a struct). More specifically that struct has a property normalized that actually returns a Vector3 also, that Vector3 also has a normalized property and so on, so what happens is NewtonSoft is trying to serialize that new Vector3 everytime and you end up in an infinite loop.

    If we had access to the Vector3 class code we could simply add the [JsonIgnore] attribute to the normalized property but we don't.

    My workaround for this was to create a custom class for this purpose:
    Code (CSharp):
    1. [System.Serializable]
    2. public class SerializableVector3{
    3.     public float x;
    4.     public float y;
    5.     public float z;
    6.  
    7.     [JsonIgnore]
    8.     public Vector3 UnityVector{
    9.         get{
    10.             return new Vector3(x, y, z);
    11.         }
    12.     }
    13.  
    14.     public SerializableVector3(Vector3 v){
    15.         x = v.x;
    16.         y = v.y;
    17.         z = v.z;
    18.     }
    19.  
    20.     public static List<SerializableVector3> GetSerializableList(List<Vector3> vList){
    21.         List<SerializableVector3> list = new List<SerializableVector3>(vList.Count);
    22.         for(int i = 0 ; i < vList.Count ; i++){
    23.             list.Add(new SerializableVector3(vList[i]));
    24.         }
    25.         return list;
    26.     }
    27.  
    28.     public static List<Vector3> GetSerializableList(List<SerializableVector3> vList){
    29.         List<Vector3> list = new List<Vector3>(vList.Count);
    30.         for(int i = 0 ; i < vList.Count ; i++){
    31.             list.Add(vList[i].UnityVector);
    32.         }
    33.         return list;
    34.     }
    35. }
    Whenever you serialize a class make sure to convert all your Vector3 to SerializableVector3 and vice-versa when you deserialize. I use the ISerializable interface (System.Runtime.Serialization) for this purpose among other things.
     
    Last edited: Apr 7, 2022
    mopthrow and illuni_dev like this.
  3. Bennyman

    Bennyman

    Joined:
    Feb 9, 2016
    Posts:
    13
    Thanks you Ensiferum888 for your fast answer and for the explanations.

    I tried to create the class by copying/pasting your code in a new SerializableVector3.cs script but I get some errors.
    It seems that I should add some namespace like unityengine and System.Collections.Generic but it's not enough.
    Also the method UnityVector has no parenthesis after it's declaration, is it normal?

    "Whenever you serialize a class make sure to convert all your Vector3 to SerializableVector3 and vice-versa when you deserialize. I use the ISerializable interface (System.Runtime.Serialization) for this purpose among other things. "
    => Could you give me a small example please ? (I'm self taught coder)

    Thanks for your help !

    Ben
     
  4. ensiferum888

    ensiferum888

    Joined:
    May 11, 2013
    Posts:
    317
    Hi Bennyman!

    You are correct you do need the standard namespaces. I also made a typo for the UnityVector it's not a method but a property, I updated the code with the proper get{} block.

    I'm at work right now but I can absolutely give you some examples later today. I suggest you read up on ISerializable Interface (System.Runtime.Serialization) | Microsoft Docs

    I'll give you a more personalized explanation later.
     
  5. Bennyman

    Bennyman

    Joined:
    Feb 9, 2016
    Posts:
    13
    Thanks again Ensiferum888.
    It is working now :)
    I tried to understand the page your mentioned. Even if I understand the concept, I don't understand the details, so I didn't tried to implement it
    Anyway, I kind of harcoded the 2 ways conversion in my script and it work. (I also created the same for Vector4).

    Many thanks again !
    Ben
     
    ensiferum888 likes this.
  6. dhindman

    dhindman

    Joined:
    Jan 28, 2016
    Posts:
    17
    You can use the ReferenceLoopHandling setting when serializing to address this. Worked perfectly for my needs.

    Output in my case:
    upload_2022-7-13_18-54-40.png
     
    Last edited: Jul 14, 2022
  7. Frakcture

    Frakcture

    Joined:
    Jun 30, 2022
    Posts:
    2
  8. uwakaranai

    uwakaranai

    Joined:
    Jan 22, 2021
    Posts:
    1
    You could convert your Vector3 into a float array to serialize:
    var newArr = new float[3]
    {
    yourVector3.x,
    yourVector3.y,
    your Vector3.z
    }
    Then, to Deserialize:
    var jsonArr = your method of reading the serialized newArr, which returns a JArray Object.
    var vectorArr = JsonConvert.DeserializeObject<float[]>(jsonArr.ToString());
    var myVector = new Vector3(vectorArr[0], vectorArr[1], vectorArr[2]);

    Not super fancy, but it works.
     
    mopthrow likes this.
  9. zxc76_die

    zxc76_die

    Joined:
    Apr 10, 2018
    Posts:
    9
  10. diegoop

    diegoop

    Joined:
    May 7, 2014
    Posts:
    8
    Just in case someone else is going through this thread looking to fix this, @dhindman answer is the right one, as it uses NewtonSoft's implementation with no need to add any fix on your code or reinvent the wheel.

    To make it easy here is the code you have to use when serializing your json to ignore self referencing loop:

    string json = JsonConvert.SerializeObject(_yourObject, Formatting.Indented, new JsonSerializerSettings
    {
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
    });
     
  11. MaskedMouse

    MaskedMouse

    Joined:
    Jul 8, 2014
    Posts:
    1,064