白黒羊

【Newtonsoft/Json.NET】JsonSerializationException: Self referencing loop detected に対応する

Newtonsoft Json for Unity

最近UnityでJsonを取り扱う際にはNewtonsoftのJson.NETを使っています。
Unityでオフィシャルにサポートしてくれていて、とても使いやすいです。

https://docs.unity3d.com/Packages/com.unity.nuget.newtonsoft-json@2.0/manual/index.html

エラーメッセージ

さて、UnityEngine.Vector2 型をfieldとして持つクラスをSerializeしようとしたところ以下のようなエラーメッセージが表示され、うまくできませんでした。

JsonSerializationException: Self referencing loop detected for property 'normalized' with type 'UnityEngine.Vector2'. Path '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.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.JsonSerializerSettings settings) (at <bc3985d37b0241b48fc21474b2de25bd>:0)Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value) (at <bc3985d37b0241b48fc21474b2de25bd>:0)Project.Scripts.Domain.Singleton.CachingData.Write[T] (System.String key, T value) (at Assets/Project/Scripts/Domain/Singleton/CachingData.cs:44)

解決策

子要素が親要素を参照していることで循環が生じてしまっていることが問題のようなので、JsonSerializerSettingsReferenceLoopHandling.Ignoreをセットしてあげることで子要素からの参照を無視することにしました。

これで問題なくシリアライズできます。

var serialized = JsonConvert.SerializeObject(value, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });

参考

c# – JSON.Net Self referencing loop detected – Stack Overflow