You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Source type: Dictionary<int, AbstractCustomType> where AbstractCustomType has concrete subclasses that each have a custom contract resolver implemented. Adding a JsonConverter for the abstract type did not help. Using the Newtonsoft Json for Unity version 3.2.1
publicabstractclassAbstractCustomType{//defines several abstract methods}publicclassConcreteImplA:AbstractCustomType{publicintserializableValue;//implements those abstract methods}publicclassConcreteImplAResolver:JsonConverter{publicoverridevoidWriteJson(JsonWriterwriter,objectvalue,JsonSerializerserializer){ConcreteImplAv=(ConcreteImplA)value;JObjecto=newJObject();o.Add(newJProperty("class",v.GetType().AssemblyQualifiedName));o.Add(newJProperty("value",v.serializableValue));o.WriteTo(writer);}publicoverrideobjectReadJson(JsonReaderreader,TypeobjectType,objectexistingValue,JsonSerializerserializer){JObjectjObject=JObject.Load(reader);stringid=(string)jObject.GetValue("class");ConcreteImplArunObj=Activator.CreateInstance(Type.GetType(id));runObj.serializableValue=(int)jObject.GetValue("value");returnrunObj;}publicoverrideboolCanConvert(TypeobjectType){returntypeof(ConcreteImplA).IsAssignableFrom(objectType);}}
However, when the concrete implementation contains another object (that also has a converter) that then contains a dictionary of these types, it fails:
publicclassConcreteImplB:AbstractCustomType{publicChildGroupgrouping=newChildGroup();}// with defined JsonConverter specified in the ContractResolverpublicclassChildGroup{publicDictionary<int,AbstractCustomType>childObjects;//this dictionary is the source of the errorpublicChildGroup(){childObjects=newDictionary<int,AbstractCustomType>{{0,newConcreteImplA(){serializableValue=1}}};}}// with defined JsonConverter specified in the ContractResolver
I use a custom Attribute to create/resolve the converters, which shouldn't impact the behavior, it just lets me more quickly handle them and don't have to constantly update the ContractResolver class and instead use the attribute on the class itself and make the Converter a contained child class (which can access private/protected fields):
(If you want to yoink that attribute and means of registering converters and add it to the package, by all means, go for it; I did it that way to make my life easier and comparable method didn't exist or I couldn't find it. While you're at it, fix the existing converters for Unity structs, it keeps trying to deserialize the read-only property magnitude on things like Vector3).
The inheritance of my classes are also rather involved, as there's the runtime object which takes properties from a serializable object, but which can be modified to be different than the base serialized version (think Minecraft Items, there's the Item which defines what a stick is, then there's the ItemStack which represents this specific stick: the two serialize differently as the former is an asset that may be referenced hundreds of times by the instances and the later is a runtime mutable instance derived from the asset which has its own modified values). Some of these modifiable properties are collections containing more mutable instances ("this is a Bag of Sticks and Stones, there's a stick in slot 0, a stone in slot 1, slot 2 is empty...").
So I'm not actually using reflection to create the new instances, but rather looking up in the ItemRegistry the Asset by its name-id and asking it for a new instance, but it functions similarly to CreateInstance(GetType(...)). Entire project in its current state is available. The json call is here. The first SerializeObject call on 70 works, the one on 73 does not.
(If you clone the repo to run this in Unity yourself, I'm using Unity 2022.3.22, the #if on 43 needs to be inverted to simulate non-editor behavior, then enter play mode in the Main scene (it should open with that scene active, otherwise it is in Assets/Scenes/Main), click the thing shooting bullets, add anything that creates more bullets to the timeline (Split Shot, Death Blossom, 60 Degree Spray are all in the card pool, which one shows up, if any, is going to be random), then click Save Asset and it will print the string in the console).
The text was updated successfully, but these errors were encountered:
Source type
Source type:
Dictionary<int, AbstractCustomType>
whereAbstractCustomType
has concrete subclasses that each have a custom contract resolver implemented. Adding a JsonConverter for the abstract type did not help. Using the Newtonsoft Json for Unity version 3.2.1Expected behavior
This works:
Producing this json:
However, when the concrete implementation contains another object (that also has a converter) that then contains a dictionary of these types, it fails:
Expected JSON:
Actual behavior
ArgumentException: Could not determine JSON object type for type System.Collections.Generic.KeyValuePair
2[System.Int32,AbstractCustomType].`Steps to reproduce
Additional details & Repo
I use a custom Attribute to create/resolve the converters, which shouldn't impact the behavior, it just lets me more quickly handle them and don't have to constantly update the ContractResolver class and instead use the attribute on the class itself and make the Converter a contained child class (which can access private/protected fields):
(If you want to yoink that attribute and means of registering converters and add it to the package, by all means, go for it; I did it that way to make my life easier and comparable method didn't exist or I couldn't find it. While you're at it, fix the existing converters for Unity structs, it keeps trying to deserialize the read-only property
magnitude
on things likeVector3
).The inheritance of my classes are also rather involved, as there's the runtime object which takes properties from a serializable object, but which can be modified to be different than the base serialized version (think Minecraft Items, there's the
Item
which defines what a stick is, then there's theItemStack
which represents this specific stick: the two serialize differently as the former is an asset that may be referenced hundreds of times by the instances and the later is a runtime mutable instance derived from the asset which has its own modified values). Some of these modifiable properties are collections containing more mutable instances ("this is aBag
ofSticks
andStones
, there's a stick in slot 0, a stone in slot 1, slot 2 is empty...").So I'm not actually using reflection to create the new instances, but rather looking up in the ItemRegistry the Asset by its name-id and asking it for a new instance, but it functions similarly to
CreateInstance(GetType(...))
. Entire project in its current state is available. The json call is here. The first SerializeObject call on 70 works, the one on 73 does not.(If you clone the repo to run this in Unity yourself, I'm using Unity 2022.3.22, the
#if
on 43 needs to be inverted to simulate non-editor behavior, then enter play mode in the Main scene (it should open with that scene active, otherwise it is inAssets/Scenes/Main
), click the thing shooting bullets, add anything that creates more bullets to the timeline (Split Shot, Death Blossom, 60 Degree Spray are all in the card pool, which one shows up, if any, is going to be random), then click Save Asset and it will print the string in the console).The text was updated successfully, but these errors were encountered: