MaxSantos
MaxSantos

Reputation: 156

NewtonSoft Json.Net conditional serialization of object

I have a question concerning NewtonSoft Json.Net Serialization. I have searched around but have not been able to find a solution. There are some question in SO that resemble this one by the title, but none present this scenario.

What i need is to prevent certain objects from being serialized under certain conditions.

Example: Given this class:

class A
{
    B b;
}

We can prevent B from being serialized by writing:

class A
{
    B b;
    public bool ShouldSerializeb()
    {
        return false; //validate the condition you want.
    }
}

But if we have multiple Bs, we end up having to write a function for each one:

class A
{
    B b;
    B bb;
    B bbb;
    public bool ShouldSerializeb()
    {
        return false; //validate the condition you want.
    }

    public bool ShouldSerializebb()
    {
        return false; //validate the condition you want.
    }

    public bool ShouldSerializebbb()
    {
        return false; //validate the condition you want.
    } 
}

There is another way: Use a Contract resolver

public class ShouldSerializeContractResolver : DefaultContractResolver
{
    public new static readonly ShouldSerializeContractResolver Instance 
     = new ShouldSerializeContractResolver();
    protected override JsonProperty CreateProperty(MemberInfo member, 
    MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        if (property.PropertyType == typeof(B))
        {
            property.ShouldSerialize =
                instance =>
                {
                    if (instance == null)
                        return false;

                    // The problem is that "instance" here is A and not B
                    // preventing the necessary validation

                    return false; //validate the condition you want.
                };
        }
        return property;
    }
}

Questions:


    class B
    {
        public bool ShouldSerialize()
        {
             return false; //validate the condition you want.
        }
    }

Thank you (I probably should post this on github, but we are so used to concentrate question in SO)

Upvotes: 2

Views: 1940

Answers (2)

Brian Rogers
Brian Rogers

Reputation: 129787

Yes, you can do this in the ContractResolver. You have the instance (of A), and you have the property (of type B), so you just need to ask the ValueProvider on the property to give you the value from the instance. That is the B that you seek. Then you can inspect the B to decide whether or not to serialize the property.

So, for example, if class B looked like this:

class B
{
    public string Name { get; set; }
    [JsonIgnore]
    public bool IsHidden { get; set; }
}

You could decide in the resolver that you only want to serialize B if IsHidden is false:

protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
    JsonProperty property = base.CreateProperty(member, memberSerialization);
    if (property.PropertyType == typeof(B))
    {
        property.ShouldSerialize = instance =>
        {
            if (instance == null) return false;

            B b = (B)property.ValueProvider.GetValue(instance);

            // validate the condition you want, for example:
            return b != null && !b.IsHidden;
        };
    }
    return property;
}

Here is a working demo: https://dotnetfiddle.net/4MbQ0q

By the way, I'm fairly certain that the instance passed to ShouldSerialize will never be null, because it doesn't make sense to ask whether a property of A should be serialized if there is no A in the first place. It doesn't hurt to have the check in there, but I don't think you need it.

Upvotes: 1

James Terry
James Terry

Reputation: 9

Could you write two methods for ShouldSerialize?

public bool ShouldSerialize(typeof(B))
{
    return false;
}

or write an overide within class B and call it as class B : A and then

Class B : A {
    public overide bool ShouldSerialize()
    {
        return false;
    }
}

Class A {
    public bool ShouldSerialize(){
        return true;
    }
}

then call b.ShouldSerialize(); or bb.ShouldSerialize();

Worth a try, may have misunderstood the question but hey oh someone else will know in time.

Upvotes: 0

Related Questions