I have this set of classes that I want to serialize/deserialize. Its called a Behaviour Tree and its in a tree structure (Composite pattern).
One problem that I solved is this (when I store subclasses in a BaseClass[ ] array, when deserialized, they should come out as the same subclasses)
Now my classes have generics. This is the base class’ decleration:
public abstract class Node<T> where T : IBlackboardHolder
it takes in an interface, but it never stores that interface in a member variable. Its only used here:
public abstract RunState Tick(T agent)
where it does stuff to T in that function.
Now, as I need type hinting to make serializing of the arrays work, here’s how the type hint of one of them look like:
"__type": "BehaviourTree.Root`1[[IUnit, Assembly-CSharp, Version=2.0.0.35553, Culture=neutral, PublicKeyToken=null]], Assembly-CSharp"
When I make edits to my code, and recompile, when I serialize again, this is how it looks like:
"__type": "BehaviourTree.Root`1[[IUnit, Assembly-CSharp, Version=2.0.0.35636, Culture=neutral, PublicKeyToken=null]], Assembly-CSharp"
The odd thing is the Version part there changed. Now when I try to deserialize the JSON string with the older Version, I get this error:
JsonTypeCoercionException: Interfaces, Abstract classes, and unsupported ValueTypes cannot be deserialized. (BehaviourTree.Node`1[[IUnit, Assembly-CSharp, Version=2.0.0.35553, Culture=neutral, PublicKeyToken=null]])
JsonFx.Json.TypeCoercionUtility.InstantiateObject (System.Type objectType, System.Collections.Generic.Dictionary`2 memberMap) (at Assets/Packages/Scripts/JsonFx.Json/TypeCoercionUtility.cs:136)
JsonFx.Json.TypeCoercionUtility.CoerceType (System.Type targetType, IDictionary value, System.Collections.Generic.Dictionary`2 memberMap) (at Assets/Packages/Scripts/JsonFx.Json/TypeCoercionUtility.cs:439)
JsonFx.Json.TypeCoercionUtility.CoerceType (System.Type targetType, System.Object value) (at Assets/Packages/Scripts/JsonFx.Json/TypeCoercionUtility.cs:359)
JsonFx.Json.TypeCoercionUtility.CoerceArray (System.Type elementType, IEnumerable value) (at Assets/Packages/Scripts/JsonFx.Json/TypeCoercionUtility.cs:598)
JsonFx.Json.TypeCoercionUtility.CoerceList (System.Type targetType, System.Type arrayType, IEnumerable value) (at Assets/Packages/Scripts/JsonFx.Json/TypeCoercionUtility.cs:457)
JsonFx.Json.TypeCoercionUtility.CoerceType (System.Type targetType, System.Object value) (at Assets/Packages/Scripts/JsonFx.Json/TypeCoercionUtility.cs:365)
JsonFx.Json.TypeCoercionUtility.SetMemberValue (System.Object result, System.Type memberType, System.Reflection.MemberInfo memberInfo, System.Object value) (at Assets/Packages/Scripts/JsonFx.Json/TypeCoercionUtility.cs:279)
JsonFx.Json.JsonReader.ReadObject (System.Type objectType) (at Assets/Packages/Scripts/JsonFx.Json/JsonReader.cs:481)
JsonFx.Json.JsonReader.Read (System.Type expectedType, Boolean typeIsHint) (at Assets/Packages/Scripts/JsonFx.Json/JsonReader.cs:304)
JsonFx.Json.JsonReader.Deserialize[Root`1] () (at Assets/Packages/Scripts/JsonFx.Json/JsonReader.cs:262)
AssetUtility.FromSerializedString[Root`1] (System.String jsonText) (at Assets/TacticsEnsemble/Scripts/Util/AssetUtility.cs:77)
AssetUtility.LoadFromLocal[Root`1] (System.String filePath) (at Assets/TacticsEnsemble/Scripts/Util/AssetUtility.cs:36)
BehaviourTreeEditorWindow.OnGUI () (at Assets/TacticsEnsemble/Scripts/AI/BehaviourTree/Editor/BehaviourTreeEditorWindow.cs:310)
System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture)
This is what I’m looking at:
JsonTypeCoercionException: Interfaces, Abstract classes, and unsupported ValueTypes cannot be deserialized. (BehaviourTree.Node`1[[IUnit, Assembly-CSharp, Version=2.0.0.35553, Culture=neutral, PublicKeyToken=null]])
It thinks it needs to deserialize to a Node
, which is an abstract base class and that shouldn’t happen. In fact, my JSON string never has Node
in its type hints.
Take note if I try to deserialize the JSON string that has the newer version (2.0.0.35636 as opposed to 2.0.0.35553), no errors happen and I get my object deserialized fine.
So, as an experiment, I changed the type hinting from
type.FullName +", "+type.Assembly.GetName().Name
to:
type.ToString() +", "+type.Assembly.GetName().Name
and type hints I get now become:
"__type": "BehaviourTree.Root`1[IUnit], Assembly-CSharp"
and that seems to have fixed my problem.
My concern is, I’m not sure if that introduces any non-obvious bugs to the deserializing process.