Ramin Bateni
Ramin Bateni

Reputation: 17415

How can I solve "Required property not found in json" error without changing the json and its corresponding class?

A)

I have a DLL library include a class like the bellow code:

public class Thing
{
    // OTHER_PROPERTIES

    //..........................

    [JsonProperty(Required = Required.Always)]
    public bool IsBook { get; set; }
}

Assumption: I have not access to the source of the Thing class.


B)

And I have a JSON like this:

{
    OTHER_PROPERTIES
}

Note: It has not a pair of name-value for IsBook

Assumption: I wont change the JSON to include IsBook in it.


C)

If I run JsonConvert.DeserializeObject<Thing>(json); then I get the following error:

Error: Required property not found in json ....


Question:

How can I write a custom code to solve the above error by observing the assumptions of the problem? (please read the above assumptions again before writing your answer.)

Upvotes: 2

Views: 8308

Answers (1)

Evk
Evk

Reputation: 101533

You can use custom contract resolver to achieve that. For example:

public class Thing
{
    [JsonProperty("Name")]
    public string Name { get; set; }
    [JsonProperty(Required = Required.Always)]
    public bool IsBook { get; set; }
}

class NeverRequiredContractResolver : DefaultContractResolver {
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        var prop = base.CreateProperty(member, memberSerialization);
        prop.Required = Required.Default;
        return prop;
    }
}

And then:

var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}",
    new JsonSerializerSettings {
        ContractResolver = new NeverRequiredContractResolver()
    });

Of course you can assign resolver globally and not pass it to every DeserializeObject:

JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
    ContractResolver = new NeverRequiredContractResolver()
};
var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}");

you can make only specific properties of specific classes non-required (and not all of them like in example above):

class CustomPropertyContractResolver : DefaultContractResolver {
    private readonly Action<MemberInfo, JsonProperty> _propFixup;
    public CustomPropertyContractResolver(Action<MemberInfo, JsonProperty> propFixup) {
        _propFixup = propFixup;
    }
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
        var prop = base.CreateProperty(member, memberSerialization);
        _propFixup?.Invoke(member , prop);
        return prop;
    }
}

JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
{
    ContractResolver = new CustomPropertyContractResolver((member, prop) => {
        if (member.DeclaringType == typeof(Thing) && member.Name == "IsBook") {
            prop.Required = Required.Default;
        }
    })
};
var test = JsonConvert.DeserializeObject<Thing>("{\"Name\":\"some name\"}");

and overall adjust example above however you wish for your specific use case.

Upvotes: 6

Related Questions