I have a unity project. Using the stock json tools at my disposal, i'm trying to deserialize an enum that uses bit flags (ie something like)
[Flags]
enum Terrain
{
NORMAL = 0,
FOREST = 1,
SWAMP = 2,
CAVE = 4
}
In json it's something like CityTerrain: "FOREST", however it seems that the deserialization doesn't like human readable string enums (it wants an integer i assume) which is especially troubling for me in the case of bit flags when i want to be able to combine flags, ie. FOREST|CAVE.
XML handled bitflag enums fine out of the box. Why does json, the superior format, seem to struggle with it so badly? Should i be making an enum wrapper for handling the deserialization of this? No matter what i do, i feel like my solution will be clunky and i will dislike it.
Ultimately it needs to be human readable and i won't accept a "solution" where my bitflag enum has to be represented as 5 in json. The entire point of this exercise is that it needs to be human readable but still deserializable.
Newtonsoft.Json
you can use a StringEnumConverter
and pass it along into
var converter = new StringEnumConverter();
var json = JsonConvert.SerializeObject(example, Formatting.Indented, converter);
and (actually optional apparently)
var example = JsonConvert.DeserializeObject<Example>(json, converter);
in my test for deserializing it seems to also work with only
var example = JsonConvert.DeserializeObject<Example>(json);
System.Text.Json
you can use the equivalent JsonStringEnumConverter
and pass it via the options like e.g.
// IncludeFields depends on whether your type uses fields or properties
// by default System.Text.Json only considers properties
// so to reflect the behavior of Newtonsoft I enabled also fields
var options = new JsonSerializerOptions() { WriteIndented = true, IncludeFields = true };
options.Converters.Add(new JsonStringEnumConverter());
var json = JsonSerializer.Serialize(example, options);
and
var example = JsonSerializer.Deserialize<Example>(json, options);
Note (also applies to JsonUtility
below): Both basically go through ToString
and Enum.Parse
so in the json it will read e.g.
"FOREST, SWAMP"
if for some reason you really want FOREST|SWAMP
instead you will have to implement your own custom JsonConverter
(Newtonsoft) or accordingly JsonConverter
(System.Text.Json).
Basically using the same and do something like (pseudo code)
// When serializing Terrain -> string
var enumString = value.ToString().Replace(", ", "|");
and
// When deserializing string -> Terrain
var enumValue = (Terrain)Enum.Parse(enumString.Replace("|", ", "));
JsonUtility
afaik there is unfortunately nothing similar. You instead have to overwrite the serialization of the entire class like e.g.
public class Example : ISerializationCallbackReceiver
{
public string Name;
[NonSerialized]
public Terrain Terrain;
public int SomeVlaue;
[SerializeField]
private string terrain;
public void OnBeforeSerialize()
{
terrain = Terrain.ToString();
}
public void OnAfterDeserialize()
{
Terrain = (Terrain)Enum.Parse(typeof(Terrain), terrain);
}
}
NOTE:
Terrain
and shall be json serialized