The documentation of the package is lacking for sure. In most cases, you shouldn’t have to write the brackets, indents or whatnot manually. The “primitives” of the JsonWriter
follow this, which tells the rules that must be followed. For example, to write a key-value pair, you must be inside of an object scope.
Usually, the thing I’ve seen that trips people using it is that they try to open a scope before nesting in adapters. For example opening an object scope, then calling context.SerializeValue(...)
expecting that the adapter for that value will write it as key-value pair. Usually, this tends to break very easily. Again, here, the error messages are lacking.
Looking at the type definitions in the Getting Started section of the package documentation, I’ll iteratively implement adapters to make the output smaller. The basic output would be:
{
"Name": "Bob",
"Health": 100,
"Position": {
"x": 10,
"y": 20
},
"Inventory": [
{
"Name": "Sword",
"Type": 0
},
{
"Name": "Shield"
"Type": 1,
},
{
"Name": "Health Potion"
"Type": 2
}
]
}
If you wanted to have the same output, but with different/shorter names, you could define a Player
adapter like this:
public void Serialize(in JsonSerializationContext<Player> context, Player value)
{
// Player will have multiple key-value fields, so we must open an object scope.
using var objectScope = context.Writer.WriteObjectScope();
// Most primitives can write key-value pairs directly.
context.Writer.WriteKeyValue("N", value.Name);
context.Writer.WriteKeyValue("H", value.Health);
// Sub-objects can use the `SerializeValue` method.
context.Writer.WriteKey("P");
context.SerializeValue(value.Position);
// Arrays can also use the `SerializeValue` method.
context.Writer.WriteKey("I");
context.SerializeValue(value.Inventory);
}
This would give:
{
"N": "Bob",
"H": 100,
"P": {
"x": 10,
"y": 20
},
"I": [
{
"Name": "Sword",
"Type": 0
},
{
"Name": "Shield",
"Type": 1
},
{
"Name": "Health Potion",
"Type": 2
}
]
}
Next, I want to serialize the Position
on a single line. I can define an adapter for the int2
type to serialize it as a value rather than an object:
public void Serialize(in JsonSerializationContext<int2> context, int2 value)
{
// Serializes as a value.
context.Writer.WriteValue($"{value.x}, {value.y}");
// Serializes as an object. This would be equivalent to the default behaviour.
// using var objectScope = context.Writer.WriteObjectScope();
// context.Writer.WriteKeyValue("x", value.x);
// context.Writer.WriteKeyValue("y", value.y);
}
Similarly, you could do the same thing for the Item
:
public void Serialize(in JsonSerializationContext<Item> context, Item value)
{
context.Writer.WriteValue($"{value.Name} - {value.Type}");
}
This would give:
{
"N": "Bob",
"H": 100,
"P": "10, 20",
"I": [
"Sword - Weapon",
"Shield - Armor",
"Health Potion - Consumable"
]
}
Lastly, and this will make the output bigger, let’s say you wanted to manually write the Item
array inside the Player
adapter and bypass the adapters, you could replace:
// Arrays can use the `SerializeValue` method.
context.Writer.WriteKey("I");
context.SerializeValue(value.Inventory);
with this:
// Write the same array, but manually, by-passing the Item list and item adapters.
context.Writer.WriteKey("I");
using var arrayScope = context.Writer.WriteArrayScope();
for (var i = 0; i < value.Inventory.Length; ++i)
{
using var arrayItemValueScope = context.Writer.WriteObjectScope();
context.Writer.WriteKeyValue("Name", value.Inventory[i].Name);
context.Writer.WriteKeyValue("Type", (int)value.Inventory[i].Type);
}
Which would give:
{
"N": "Bob",
"H": 100,
"P": "10, 20",
"I": [
{
"Name": "Sword",
"Type": 0
},
{
"Name": "Shield",
"Type": 1
},
{
"Name": "Health Potion",
"Type": 2
}
]
}
Hope this helps!