EntitySerializer can write properties but ignores them when reading
I tend to lean towards using auto properties, so that's what I did when I started making components. Because they serialized ok, it took me a while before I realized they were not being deserialized. After much debugging, I came to the conclusion stated in the title.
I was unsure if this was a bug that properties do not get deserialized or if properties are not actually supported and it's a fluke that they get serialized. Wither way, I figured I'd write a issue about it.
My observations are as follows.
For the following component...
[ComponentKey("foo")]
struct Foo : IComponent
{
public int Value { get; set; }
}
I perform the following...
EntityStore store = new();
EntitySerializer serializer = new();
Entity entity = store.CreateEntity();
entity.AddComponent(new Foo { Value = 25 });
string json = serializer.WriteStoreToJson(store); // Extension method I wrote to write to string.
Console.WriteLine(json);
Console.WriteLine();
EntityStore newStore = new();
serializer.ReadIntoStore(newStore, json); // Extension method I wrote to read from string.
Foo foo = newStore.Query<Foo>().Entities.First().GetComponent<Foo>();
Console.WriteLine(foo.Value);
And it produces the following output...
[{
"id": 1,
"components": {
"foo": {"Value":25}
}
}]
0
Observe how the property value of Foo.Value is written to JSON as 25 as declared when added to the entity. However when accessing said value from a new EntityStore that the serialized entity was read into, it is now 0.
But if I make the simple change and make the property a field instead like so...
[ComponentKey("foo")]
struct Foo : IComponent
{
public int Value;
}
The output is as follows...
[{
"id": 1,
"components": {
"foo": {"Value":25}
}
}]
25
I've run into the same issue.
I've discovered that JsonSerializer from Friflo.Json.Fliox can't initialize properties on struct during deserialization (be it plain struct or record struct; be it set or init property). There are also no related parameters in SerializerOptions.
I checked also Newtonsoft and System.Text.Json implementations, they work fine with structs.
Change the enclosing (container) type from struct to class and everything will work fine. But IComponent implementer must be a struct in the end. Properties of reference types (class, record) are (de)serialized as expected. There is also no support for primary constructors atm as I can see.
I checked this issue when it was new but forgot to reply. Yes, deserialization of properties in struct are currently not supported. Deserialization of struct fields is supported.
IMHO support of properties has only low prio. Using properties in ECS components is not what I would recommend as they put a performance penalty when processing. Which is a typical goal when using an ECS.
One of my components has a field of my custom readonly record struct ValueObject implemented via primary constructor. It doesn't deserialize as well due to records exposing parameters as properties in result type shape.
Anyway, I think it's not a problem for me to rewrite my struct to use public readonly fields to enable deserialization.
By the way, what are the benefits of Friflo.Json serializer over, for example, System.Text.Json?
When starting Friflo.Json.Fliox System.Text.Json was not available.
Friflo.Json.Fliox supports Unity and is optimized for performance.
I currently don't know is both things apply to System.Text.Json.
Maybe I change serialization to System.Text.Json in future if both requirements are met.
One advantage of System.Text.Json is there are more examples and docs available in the internet.