Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NullValueHandling.Ignore with JsonConverter::WriteJson

Tags:

json

c#

json.net

I am trying to perform custom serialisation, all the happy path code works but the null value path is not behaving as I'd like.

I have set the serializer settings to NullValueHandling.Ignore and other parts of my object graph that are null (and don't use my custom serialization) have the null values removed. It looks like the Newtonsoft serializer writes to a string builder so we should be able to 'rewind' any written json tokens but I don't see how to not write anything.

Doing nothing and just returning causes the serializer to throw an exception as the json would be invalid.

Any clues?

public class SpecialConvertor : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        if (value == null || (int)value == 0)
        {
            if (serializer.NullValueHandling == NullValueHandling.Ignore)
            {
                //how to make this work?
            }
            else
            {
                writer.WriteNull();
            }
            return;
        }
        // the rest of WriteJson
    }
    // the rest of SpecialConvertor
}
like image 663
Adam Straughan Avatar asked Oct 20 '15 15:10

Adam Straughan


1 Answers

NullValueHandling is for object references. In your example, your value is an integer. To omit integer properties with default values, use the setting DefaultValueHandling = DefaultValueHandling.Ignore.

The null check in WriteJson() should not be necessary because Json.NET never calls the converter with a null value. Instead, it writes the name & null value itself -- or not, if NullValueHandling == NullValueHandling.Ignore. So checking for null and rewinding should never be required.

A null value for an object property might still get written when null value handling or default value handling are Ignore if one of your converters writes it explicitly in WriteJson. To prevent that, you can check the settings and skip nulls like so:

public class MyClassConverter : JsonConverter
{
    const string Prefix = "My Value Is: ";

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var myClass = (MyClass)value;
        writer.WriteStartObject();
        if (myClass.StringValue != null 
            || (serializer.NullValueHandling != NullValueHandling.Ignore 
                && (serializer.DefaultValueHandling & DefaultValueHandling.Ignore) != DefaultValueHandling.Ignore))
        {
            writer.WritePropertyName("StringValue");
            if (myClass.StringValue == null)
                writer.WriteNull();
            else
                serializer.Serialize(writer, Prefix + myClass.StringValue);
        }
        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var s = (string)JValue.Load(reader);
        if (s.StartsWith(Prefix))
            s = s.Substring(Prefix.Length);
        return s;
    }

    public override bool CanConvert(Type objectType) { return objectType == typeof(MyClass); }
}

[JsonConverter(typeof(MyClassConverter))]
public class MyClass
{
    public string StringValue { get; set; }
}
like image 91
dbc Avatar answered Oct 28 '22 21:10

dbc