Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserialize null regex property with json.net

Tags:

c#

json.net

The following code will throw an exception:

class SimpleClassWithRegex
{
    public Regex RegProp { get; set; }
}

[TestMethod]
public void RegexTest()
{
    string json = JsonConvert.SerializeObject(new SimpleClassWithRegex {RegProp = null}); 
    // json = {"RegProp":null}
    SimpleClassWithRegex obj = JsonConvert.DeserializeObject<SimpleClassWithRegex>(json); 
    //Above line throws a JsonSerializationException
}

This seems like strange behavior to me, can someone explain why this isn't a bug? Or perhaps suggest a workaround? Instantiating a Regex object in place of the null will of course stop this from throwing an exception.

The exception produced is:

Newtonsoft.Json.JsonSerializationException: Unexpected token when reading Regex. Path 'RegProp', line 1, position 15.

like image 996
George Richardson Avatar asked Jul 15 '16 15:07

George Richardson


1 Answers

UPDATE

It appears that this issue was fixed in release 10.0.1 (March 2017).


This looks like a bug in Json.Net's RegexConverter class. The ReadJson method looks like this:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    if (reader.TokenType == JsonToken.StartObject)
    {
        return ReadRegexObject(reader, serializer);
    }

    if (reader.TokenType == JsonToken.String)
    {
        return ReadRegexString(reader);
    }

    throw JsonSerializationException.Create(reader, "Unexpected token when reading Regex.");
}

As you can see, it is not expecting or checking for a null token from the reader, so it is falling through to the line which throws a JsonSerializationException.

You may want to report an issue linking back to this SO question.

As a workaround, you can derive your own converter from the RegexConverter and add the check:

public class ImprovedRegexConverter : RegexConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            return null;
        }
        return base.ReadJson(reader, objectType, existingValue, serializer);
    }
}

When you deserialize, pass an instance of your custom converter to the DeserializeObject method like this:

SimpleClassWithRegex obj = 
   JsonConvert.DeserializeObject<SimpleClassWithRegex>(json, new ImprovedRegexConverter());

Alterntatively, you can add a [JsonConverter] attribute to your Regex class members like this:

class SimpleClassWithRegex
{
    [JsonConverter(typeof(ImprovedRegexConverter))]
    public Regex RegProp { get; set; }
}

Fiddle: https://dotnetfiddle.net/BIqmd6

like image 137
Brian Rogers Avatar answered Nov 10 '22 04:11

Brian Rogers