3

I have the following json string as a sample for my problem:

{
    "Code": "Admin",
    "Groups":
    [
        "Administrator",
        "Superuser",
        "User"
    ]
}

Also I have a class named User with code like this...

[JsonObject(MemberSerialization.OptIn)]
public class User
{
    public User (string code)
    {
        this.Code = code;
    }

    [JsonProperty]
    public string Code { get; set; }

    [JsonProperty("Groups")]
    private List<UserGroup> groups;
    public List<UserGroup> Groups
    {
       if (groups == null)
           groups = new List<UserGroup>();
       return groups;
    }
}

... and a class named UserGroup with - for this example - only this few code lines:

public class UserGroup
{
    public UserGroup (string code)
    {
        this.Code = code;

        // Some code to fill all the other properties, just by knowing the code.
    }

    public string Code { get; set; }

    // More properties
}

Now, what I want is that the above shown JSON string would be deserialized into an instance of an User and all strings in the "Groups" array should be deserialized into a List<UserGroup> with instances from each of those strings. Also - the other way round - should a User be serialized into an JSON string with only the Code property of the contained UserGroups.

I don't deserialize normally but I create an instance of an User and populate it with this code...

Newtonsoft.Json.JsonConvert.PopulateObject(jsonString, myUserInstance);

... but if I run the code with the above shown JSON string all I get is the following exception:

Newtonsoft.Json.JsonSerializationException: 'Error converting value "Administrator" to type 'UserGroup'.

My final requirement is that, I want the UserGroup to be serialized as an array of strings only if I serialize the User. When I serialize a UserGroup standalone as a root object, it should be serialized normally (with all properties). (For comparison, in Json.Net: Serialize/Deserialize property as a value, not as an object the object is serialized as a string in all situations.)

7
  • 2
    Two options. Create a custom JsonConverter that knows how to deal with the conversion or add implicit operator to the class to know how to convert from a string Commented Aug 2, 2017 at 15:31
  • Do I have to create a JsonConverter from String to UserGroup and the other way round oder from string to List<UserGroup>? And what do you mean by adding an implicit operator? Commented Aug 2, 2017 at 15:57
  • Just curious, Why not just use this? [JsonProperty("Groups")] public string[] Groups { get; set; } Commented Aug 2, 2017 at 15:58
  • Because the UserGroup not only contains the Code property. It was just for easier understanding. Commented Aug 2, 2017 at 16:02
  • So, your input json string is more like this..{"Code":"Admin","Groups":[{"Code":"Administrator",...},{"Code":"SuperUser",...}]} and not as an array like in the post. Commented Aug 2, 2017 at 16:15

2 Answers 2

2

You are going to have to write a converter for the UserGroup

Here is a simple converter based on what was described in the question

public class UserGroupJsonConverter : JsonConverter {

    public override bool CanConvert(Type objectType) {
        return typeof(UserGroup) == objectType;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        return new UserGroup((string)reader.Value);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        writer.WriteValue(((UserGroup)value).Code);
    }
}

And then update the User to be aware of the converter by setting the ItemConverterType of the JsonProperty attribute

[JsonObject(MemberSerialization.OptIn)]
public class User {
    public User(string code) {
        this.Code = code;
    }

    [JsonProperty]
    public string Code { get; set; }

    private List<UserGroup> groups;
    [JsonProperty("Groups", ItemConverterType = typeof(UserGroupJsonConverter))]
    public List<UserGroup> Groups {
        get {
            if (groups == null)
                groups = new List<UserGroup>();
            return groups;
        }
    }
}

This would now allow for the JSON in the example

{
    "Code": "Admin",
    "Groups":
    [
        "Administrator",
        "Superuser",
        "User"
    ]
}

to be deserialized as desired

var user = JsonConvert.DeserializeObject<User>(json);

and to be serialized back into the same format.

var json = JsonConvert.SerializeObject(user);
Sign up to request clarification or add additional context in comments.

2 Comments

And if I do it like this and for example don't want to serialize my user, but maybe the usergroup itself, it doesn't uses this converter (if I don't tell it to), but will serialize it normally, with property names etc., right?
@ChristophMett, Yes. In the above example the attribute was applied only to the Groups property on the User object. if you want to just serialize the UserGroup object on its own the converter does not apply.
0

Administrator is a string, UserGroup is an object so this is a type mismatch. The valid JSON for the scenario laid out in your code is:

{
    "Code": "Admin",
    "Groups":
    [
        {
            "Code":"Administrator"
        },
        {
            "Code":"Superuser"
        },
        {
            "Code":"User"
        }
    ]
}

1 Comment

Generally this is totally correct but in my sample, I don't want to save the whole object structure of UserGroup in the JSON string but only the code. The code property is enough for my code to get the whole UserGroup instance. So, to not save redundant data (what, I know, is one almost essential part of JSON) I only want to save the string from the code property in the JSON, and also want the deserialization to get the whole UserGroup instance just from the code string.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.