Emre Tuna
Emre Tuna

Reputation: 115

Newtonsoft Json Serialization just for specific property

I've two classes and they have an aggregation relationship from one to another

public class Issue
{
    //---
    //tons of other properties
    //---
    
    [JsonProperty("key")]
    public string Key { get; set; }

    [JsonProperty("fields")]
    public Fields Fields { get; set; }

}

public class Fields
{
     //---
     //tons of other properties
     //---
     
     [JsonProperty("customfield_10202")]
     public object Customfield10202 { get; set; }
}

taken a json result like this when I use json serializer with contract resolver

{
 "customfield_10202": "value"
}

Here are the contact resolver and operation of serialization

string json = JsonConvert.SerializeObject(fields, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new DynamicContractResolver("customfield_10202") });

public class DynamicContractResolver : DefaultContractResolver
{
    private readonly string _propertyName;

    public DynamicContractResolver(string propertyName)
    {
        _propertyName = propertyName;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        
        properties =properties.Where(p => p.PropertyName == _propertyName ? true :false).ToList();

        return properties;
    }
}

but I expect result of json like this

{
    "fields": {
        "customfield_10202": "value"
    }
}

I can solve this situation easy way but it doesn't seem right. how can I take a result of json that I mentioned without using a string variable

string json_data = "{ \"fields\": " + json + "}";

Upvotes: 0

Views: 960

Answers (1)

Peter Csala
Peter Csala

Reputation: 22829

Let's suppose you have the following Issue instance:

var issue = new Issue
{
    Key = "1",
    Fields = new Fields
    {
        Customfield10202 = "value"
    }
};

In order to be able to serialize

  • fields from the Issue class and
  • customfield_10202 from the Fields class

you need to pass both names to the resolver.

So, instead of receiving a single string in the ctor you should anticipate a collection of strings:

public class DynamicContractResolver : DefaultContractResolver
{
    private readonly string[] _properties;

    public DynamicContractResolver(string[] properties)
    {
        _properties = properties;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        return properties.Where(p => _properties.Contains(p.PropertyName)).ToList();
    }
}

The usage would change like this:

var properties = new[] {"fields", "customfield_10202"};
string json = JsonConvert.SerializeObject(issue, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new DynamicContractResolver(properties) });

The generated output will be as desired:

{
  "fields": {
    "customfield_10202": "value"
  }
}

Upvotes: 1

Related Questions