Home > Mobile >  Deserialization of json list returns as much as property count list
Deserialization of json list returns as much as property count list

Time:06-02

I have a json value like this:

[{"query":[{"number":"0000-2022-64129734 / 19:26"},{"location":"xx"},{"date":"01.06.2022"},{"querytype":"uu"},{"reason":"TEST"},{"identitytype":"xx"}]},{"identity":[{"name":"xx"},{"surname":"xx"},{"id":"xx"},{"mothername":"xx"},{"fathername":"xx"},{"birthlocation":"xx"},{"birthday":"05"},{"birthmonth":"05"},{"birthyear":"1964"},{"birthlocationCity":"xx"}]},{"criminal_record_list":[[{"crime":"xx"},{"value":3}]]}]

and my class is like that:

[JsonObject]
public class CrimeResultModel
{
    [JsonProperty("criminal_record_list")]
    public List<List<criminal_record_list>> criminal_record_list{ get; set; }

    [JsonProperty("query")]
    public List<query> query{ get; set; }

    [JsonProperty("identity")]
    public List<identity> identity{ get; set; }
    public long CriminalRecordType { get; set; }
}



public class criminal_record_list
{
    [JsonProperty("crime")]
    public string crime{ get; set; }

    [JsonProperty("value")]
    public int value{ get; set; }
}

public class query
{
    public string number{ get; set; }
    public string location{ get; set; }
    public string date{ get; set; }
    public string querytype{ get; set; }
    public string reason{ get; set; }
    public string identitytype{ get; set; }

}


public class identity
{
    public string name{ get; set; }
    public string surname{ get; set; }
    public string id{ get; set; }
    public string mothername{ get; set; }
    public string fathername{ get; set; }
    public string birthlocation{ get; set; }

    public string birthday{ get; set; }
    public string birthmonth{ get; set; }
    public string birthyear{ get; set; }
    public string birthlocationCity{ get; set; }
}
}



var result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CrimeResultModel>>(jsonString);

When i try to deserialize my json, it returns list. And list count is same with property count. every property have their own list as expected but these lists also same count as number of the properties of class.I don't know what to do. Sorry for my English.

Here is the result:

enter image description here

CodePudding user response:

Your situation is very similar to the one from Serialize list of objects with string properties to json array of objects: your JSON contains arrays of single-property objects, and you would like to map those array to POCOs with multiple properties corresponding to the singleton properties in the corresponding array of objects. Your situation differs only in that every type of object in your JSON is represented as an array of objects, rather than just one type.

Thus you can generalize ObjectAsObjectArrayConverter<TObject> from this answer to handle all c# types that will be serialized as JSON objects, then use it to deserialize your JSON.

First, define the following custom JsonConverter:

public class ObjectAsObjectArrayConverter : JsonConverter
{
    // Generalized from this answer https://stackoverflow.com/a/72354204/3744182
    // By https://stackoverflow.com/users/3744182/dbc
    // To https://stackoverflow.com/questions/72352865/serialize-list-of-objects-with-string-properties-to-json-array-of-objects
    static IContractResolver DefaultResolver { get; } = JsonSerializer.Create().ContractResolver;
    readonly IContractResolver resolver;

    public ObjectAsObjectArrayConverter() : this(DefaultResolver) { }
    public ObjectAsObjectArrayConverter(IContractResolver resolver) => this.resolver = resolver ?? throw new ArgumentNullException(nameof(resolver));

    public override bool CanConvert(Type objectType)
    {
        if (objectType.IsPrimitive || objectType == typeof(string))
            return false;
        if (!(resolver.ResolveContract(objectType) is JsonObjectContract contract))
            return false;
        if (contract.DefaultCreator == null)
            return false;
        return true;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var contract = (serializer.ContractResolver.ResolveContract(value.GetType()) as JsonObjectContract) ?? throw new ArgumentException("Wrong contract type");
        writer.WriteStartArray();
        foreach (var property in contract.Properties.Where(p => ShouldSerialize(p, value)))
        {
            var propertyValue = property.ValueProvider.GetValue(value);
            if (propertyValue == null && (serializer.NullValueHandling == NullValueHandling.Ignore || property.NullValueHandling == NullValueHandling.Ignore))
                continue;
            writer.WriteStartObject();
            writer.WritePropertyName(property.PropertyName);
            if (propertyValue == null)
                writer.WriteNull();
            else if (property.Converter != null && property.Converter.CanWrite)
                property.Converter.WriteJson(writer, propertyValue, serializer);
            else
                serializer.Serialize(writer, propertyValue);
            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }

    protected virtual bool ShouldSerialize(JsonProperty property, object value) =>
        property.Readable && !property.Ignored && (property.ShouldSerialize == null || property.ShouldSerialize(value));

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (existingValue == null)
            existingValue = serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();

        switch (reader.MoveToContentAndAssert().TokenType)
        {
            case JsonToken.Null:
                return (object)null;
        
            case JsonToken.StartArray:
                while (reader.ReadToContentAndAssert().TokenType != JsonToken.EndArray)
                {
                    switch (reader.TokenType)
                    {
                        case JsonToken.StartObject:
                            serializer.Populate(reader, existingValue);
                            break;
                        default:
                            throw new JsonSerializationException("Unexpected token type "   reader.TokenType.ToString());
                    }
                }
                break;

            case JsonToken.StartObject:
                serializer.Populate(reader, existingValue);
                break;

            default:
                throw new JsonSerializationException("Unexpected token type "   reader.TokenType.ToString());
        }
        return existingValue;
    }
}

public static partial class JsonExtensions
{
    public static JsonReader ReadToContentAndAssert(this JsonReader reader) =>
        reader.ReadAndAssert().MoveToContentAndAssert();

    public static JsonReader MoveToContentAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (reader.TokenType == JsonToken.None)       // Skip past beginning of stream.
            reader.ReadAndAssert();
        while (reader.TokenType == JsonToken.Comment) // Skip past comments.
            reader.ReadAndAssert();
        return reader;
    }

    public static JsonReader ReadAndAssert(this JsonReader reader)
    {
        if (reader == null)
            throw new ArgumentNullException();
        if (!reader.Read())
            throw new JsonReaderException("Unexpected end of JSON stream.");
        return reader;
    }
}

Next, modify your CrimeResultModel as follows, leaving criminal_record_list, query and identity unchanged:

public class CrimeResultModel
{
    [JsonProperty("criminal_record_list")]
    public List<criminal_record_list> criminal_record_list{ get; set; }

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

    [JsonProperty("identity")]
    public identity identity { get; set; }
    
    public long CriminalRecordType { get; set; }
}

And now you will be able to do:

var inputSettings = new JsonSerializerSettings
{
    Converters = { new ObjectAsObjectArrayConverter() },
};
var result = JsonConvert.DeserializeObject<CrimeResultModel>(jsonString, inputSettings);

Demo fiddle here.

CodePudding user response:

try this

    json = json.Replace("},{", ",");

    var jsonArr = JArray.Parse(json);
    Data data = new Data
    {
        Query = ((JObject)jsonArr[0]).Properties().Where(p => p.Name == "query").First().Value.First.ToObject<query>(),
        Identity = ((JObject)jsonArr[0]).Properties().Where(p => p.Name == "identity").First().Value.First.ToObject<identity>(),
        CriminalRecordList = ((JObject)jsonArr[0]).Properties().Where(p => p.Name == "criminal_record_list").First().Value.First.ToObject<List<criminal_record_list>>()
    };

class Data

public class Data
{
    public Query Query { get; set; }
    public Identity Identity { get; set; }
    public List<criminal_record_list> CriminalRecordList { get; set; }
}

  • Related