Reputation: 3338
My application receives a JSON object as:
{
"names": [
"name_1",
"name_2"
]
}
I want to deserialize it to a list of Person
object, defined as:
class Person
{
public string Name { set; get; }
}
Currently, I am deserializing the JSON object to a list of strings then create a list of Person
manually like the following:
var names = JsonConvert.DeserializeObject<List<string>>(json);
var people = new List<Person>();
foreach(var name in names)
people.Add(new Person(){ Name = name });
Instead, I am interested in something like the following:
var people = JsonConvert.DeserializeObject<List<Person>>(json);
I am implementing the Person
deserializer as:
public class PersonJsonConverter : JsonConverter
{
private readonly Dictionary<string, string> _propertyMappings;
public PersonJsonConverter()
{
_propertyMappings = new Dictionary<string, string>
{
{"name", nameof(Person.Name)}
};
}
public override bool CanConvert(Type objectType)
{
return objectType.GetTypeInfo().IsClass;
}
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
object instance = Activator.CreateInstance(objectType);
var props = objectType.GetTypeInfo().DeclaredProperties.ToList();
JObject obj = JObject.Load(reader);
foreach (JProperty jsonProperty in obj.Properties())
{
if (!_propertyMappings.TryGetValue(jsonProperty.Name, out var name))
name = jsonProperty.Name;
PropertyInfo prop = props.FirstOrDefault(
pi => pi.CanWrite && pi.Name == name);
prop?.SetValue(
instance,
jsonProperty.Value.ToObject(prop.PropertyType, serializer));
}
return instance;
}
}
This deserializer can deserilize object such as:
{
"names": [
"name": "name_1",
"name": "name_2"
]
}
but not
{
"names": [
"name_1",
"name_2"
]
}
Note that my application can receive both types of JSON objects, so better to have a common deserializer for both types.
Upvotes: 0
Views: 213
Reputation: 1985
Please try below:
class Person
{
public string Name { set; get; }
}
public class PersonJsonConverter : JsonConverter
{
// private readonly Dictionary<string, string> _propertyMappings;
public PersonJsonConverter()
{
/*_propertyMappings = new Dictionary<string, string>
{
{"name", nameof(Person.Name)}
};*/
}
public override bool CanConvert(System.Type objectType)
{
return objectType.GetTypeInfo().IsClass;
}
public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer)
{
object instance = Activator.CreateInstance(objectType);
// List<T> implements the non-generic IList interface
IList list = (IList)instance;
var typeInfo = objectType.GetTypeInfo();
var props = typeInfo.DeclaredProperties.ToList();
PropertyInfo prop = props.FirstOrDefault(pi => pi.PropertyType == typeof(Person));
JObject obj = JObject.Load(reader);
var namesArray = obj["names"]; // you can use this instead of for loop on obj.Properties.
/*foreach (JProperty jsonProperty in obj.Properties())
{
if (jsonProperty.Name == "names")
{
var namesArray = JArray.Parse(jsonProperty.Value.ToString());
*/
if (namesArray.Type == JTokenType.Array && prop != null)
{
foreach (var ja in namesArray)
{
object personInstance = Activator.CreateInstance(prop.PropertyType);
PropertyInfo personNamePropInfo = prop.PropertyType.GetProperty(nameof(Person.Name));
personNamePropInfo.SetValue(personInstance,
Convert.ChangeType(ja, personNamePropInfo.PropertyType), null);
list.Add(personInstance); // Whatever you need to add
}
}
/* break;
}
}*/
return instance;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
and use it like below:
var samplejson = @"{
""names"": [
""name_1"",
""name_2""
]
}";
var obj = JsonConvert.DeserializeObject<List<Person>>(samplejson, new JsonConverter[] { new PersonJsonConverter() });
The other json does not seem to be valid json.
Upvotes: 1
Reputation: 27001
You have to deserialize names
to something like a JArray
, then foreach
each entry with a new Person('name')
. The JSON as you received it just doesn't match your desired schema. You have to manually transform it.
Upvotes: 1