0

I'm using Json.Net to parse a JSON file. This file contains a key called "AthleteType". If the athlete type value is "SoccerPlayer", I want to require the user to have inputted a "RightOrLeftFoot" key value. But if the athlete type was golfer, the "RightOrLeftFoot" could be left out. Is it possible to use conditional requirements in json.net?

Pseudo code:

public class Athlete
{
    [JsonProperty(Required = Required.Always)]
    public string AthleteType { get; set; }

    [JsonProperty(Required = if(AthleteType == SoccerPlayer))]
    public string RightOrLeftFood{ get; set; }
}
Izzo
  • 4,461
  • 13
  • 45
  • 82
  • You cannot use a non-static field inside a JsonProperty like you are thinking. JsonProperty does not have any way of using a comparison to look up a Required enum based on its attributes. You can use comparisons within the getter and setter though – Jawad Jan 21 '20 at 17:24
  • You should be able to do this with [tag:jsonschema] validation, see [jsonSchema attribute conditionally required](https://stackoverflow.com/q/38717933/3744182). [Json.NET schema](https://www.newtonsoft.com/jsonschema) is a second, separately licensed product though. Otherwise, since a JSON object is an *unordered* set of name/value pairs, you could do this in an `[OnDeserialized]` method, see e.g. [Validate Json data while calling DeserializeObject( … )](https://stackoverflow.com/a/42285017/3744182). – dbc Jan 22 '20 at 20:34

2 Answers2

2

How about an object oriented approach?

public abstract class Athlete
{
    [JsonProperty(Required = Required.Always)]
    public string AthleteType { get; set; }

    // and whatever else is relevant for all athletes
}

public class SoccerPlayer : Athlete
{
    // Why is that a string? I would use an enum: Left/Right/Both (for players with no favorite foot)
    [JsonProperty(Required = Required.Always)]
    public string RightOrLeftFood{ get; set; }
}

public class GolfPlayer : Athelte
{
    // Here you have whatever is relevant for golf players
}

Then you can check what is the value of AthleteType in the Json and deserialize the specific type based on the string.

Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
0

I tested it out with this code and seems to work consistently. Only thing that is "required" is that you must provide the property of RightOrLeftFoot whether it includes value or not.

I created a test class Athlete with two attributes, AthleteType and RightOrLeftFoot to see how i can provide you an example on how to use getter setter.

    public class Athlete
    {
        private string rightOrLeftFoot;

        [JsonProperty(Required = Required.Always)]
        public string AthleteType { get; set; }

        [JsonProperty(Required = Required.AllowNull)]
        public string RightOrLeftFood { 
            get { return rightOrLeftFoot; } 
            set 
            {
                if (AthleteType.Equals("SOCCER") && string.IsNullOrEmpty(value))
                    throw new ApplicationException("value is required for RightOrLeftFood when AthleteType is SOCCER");
                rightOrLeftFoot = value;
            } 
        }
    }

When I work with getters and setters, i like to use a local variable. In the setter, you can check whether the AthleteType is defined as SoccerPlayer or whatever you are interested in comparing, then go about the deserialization.

Athlete athlete = JsonConvert.DeserializeObject<Athlete>(json);

Exception will be thrown ONLY if the attribute AthleteType is "SOCCER" and value for RightOrLeftFoot is null / empty string.

Jawad
  • 11,028
  • 3
  • 24
  • 37