Note: re: related questions - they have similar titles but their titles are misleading: reading them reveals they're about a different situation, they're worried about INCOMING null, whereas I need a null but don't have one.
TL:DR: why is Json generating an error when no error should be generated? Why is it not accepting the null output? Why does it work when the input is null and the output is null - but not when the input is non-null and the output is null?
I have a custom JsonConverter that interprets a json object that is a polymorphic class, and generates the correct subclass based on a child property.
public class Metadata // base class
public class MetadataText : Metadata
public class MetadataImage : Metadata
... etc
Each class with a child Metadata property has it marked as nullable:
public class Author
{
[CanBeNull] public Metadata metadata { get; set; }
}
This works fine for many variations of "metadata" in the incoming JSON. However... I have no control over the incoming json - huge files from a third party - and annoyingly they sometimes return "{}" where they should have returned "null".
i.e.
...
"author":{
"metadata":
{}
}
...which SHOULD BE:
"author":{
"metadata": null
}
This seems to be generating a huge number of fake errors on deserialization (currently captured and logged to console using a custom error-handler)
var jsonSettings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
Error = HandleDeserializationError // just outputs the error
};
I can't seem to find a way to get rid of those fake errors:
Value cannot be null.
Parameter name: value, path = [0].[OMITTED].author.metadata
class MetadataConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Metadata).IsAssignableFrom(objectType);
}
// has no effect: [CanBeNull]
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject item = JObject.Load(reader);
if( item.Count == 0 )
{
Debug.Log( "Found a Metadata with count = 0; "+reader.TokenType+", "+reader.Path+", "+reader.Value+" -- item: "+item.Type+", "+item.Parent?.Parent+", "+item.Path+", "+item.Properties().Count() );
return (Metadata)null; // should be OK!
}
switch (item["command"].Value<string>())
{
case "open_url": return item.ToObject<Metadata_OpenURL>();
case "search": return item.ToObject<Metadata_Search>();
case "mclick": return item.ToObject<Metadata_MClick>();
case "msearch": return item.ToObject<Metadata_MSearch>();
default: return item.ToObject<Metadata>();
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
[JsonConverter(typeof(MetadataConverter))] public Metadata? Metadata {get;set;}?CanBeNulldoesn't affect deserialization, it affects the compiler's nullability checks. An empty Dictionary/object isn'tnullanyway. If you expectMetadatato be null, the property should beMetadata?.