CSharp · Console
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization.Formatters;
using System.IO;
using System.Data;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
// https://stackoverflow.com/questions/29449641/deserialize-json-when-type-can-be-different#29449760
public class JsonSingleOrEmptyArrayConverter<T> : JsonConverter where T : class
{
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override bool CanWrite { get { return false; } }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var contract = serializer.ContractResolver.ResolveContract(objectType);
if (!(contract is Newtonsoft.Json.Serialization.JsonObjectContract || contract is Newtonsoft.Json.Serialization.JsonDictionaryContract))
{
throw new JsonSerializationException(string.Format("Unsupported objectType {0} at {1}.", objectType, reader.Path));
}
switch (reader.SkipComments().TokenType)
{
case JsonToken.StartArray:
{
int count = 0;
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonToken.Comment:
break;
case JsonToken.EndArray:
return existingValue;
default:
{
count++;
if (count > 1)
throw new JsonSerializationException(string.Format("Too many objects at path {0}.", reader.Path));
existingValue = existingValue ?? contract.DefaultCreator();
serializer.Populate(reader, existingValue);
}
break;
}
}
// Should not come here.
throw new JsonSerializationException(string.Format("Unclosed array at path {0}.", reader.Path));
}
case JsonToken.Null:
return null;
case JsonToken.StartObject:
existingValue = existingValue ?? contract.DefaultCreator();
serializer.Populate(reader, existingValue);
return existingValue;
default:
throw new InvalidOperationException("Unexpected token type " + reader.TokenType.ToString());
}
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
public static partial class JsonExtensions
{
public static JsonReader SkipComments(this JsonReader reader)
{
while (reader.TokenType == JsonToken.Comment && reader.Read())
;
return reader;
}
}
// https://stackoverflow.com/questions/29449641/deserialize-json-when-type-can-be-different#29449760
public class User
{
//some other fields...
[JsonConverter(typeof(JsonSingleOrEmptyArrayConverter<Personal>))]
public Personal personal { get; set; }
//some other fields...
}
public class Personal
{
public byte political { get; set; }
public string[] langs { get; set; }
public string religion { get; set; }
public string inspired_by { get; set; }
public byte people_main { get; set; }
public byte life_main { get; set; }
public byte smoking { get; set; }
public byte alcohol { get; set; }
}
public class TestClass
{
public static void Test()
{
string json0 = @"{ personal: null }";
string json1 = @"{ personal: [] }";
string json2 = @"{
personal: {
religion: 'Нет',
smoking: 1,
alcohol: 4
} //when not empty.
}";
string json3 = @"{
personal: [/* Some Comment */{
religion: 'Нет',
smoking: 1,
alcohol: 4
}/* Some Comment */] //when not empty.
}";
string json4 = @"{
personal: [
/* Some Comment */{
religion: 'Нет',
smoking: 1,
alcohol: 4
}/* Some Comment */,
/* Some Comment */{
religion: 'Нет',
smoking: 1,
alcohol: 4
}/* Some Comment */,
] //when not empty.
}";
string json5 = @"{
personal: [
/* Some Comment */{
religion: 'Нет',
smoking: 1,
alcohol: 4
}";
Test(json0, p => Assert.IsTrue(p == null));
Test(json1, p => Assert.IsTrue(p == null));
Test(json2, p => Assert.IsTrue(p != null && p.religion == "Нет"));
Test(json3, p => Assert.IsTrue(p != null && p.religion == "Нет"));
try
{
Test(json4, p => { throw new AssertionFailedException("Should have failed"); } );
}
catch (JsonException ex)
{
Console.WriteLine("Caught expected exception: " + ex.Message);
}
try
{
Test(json5, p => { throw new AssertionFailedException("Should have failed"); });
}
catch (JsonException ex)
{
Console.WriteLine("Caught expected exception: " + ex.Message);
}
Console.WriteLine("Done with tests.");
}
static void Test(string json, Action<Personal> validate)
{
var user = JsonConvert.DeserializeObject<User>(json);
var newJson = JsonConvert.SerializeObject(user, Formatting.Indented);
Console.WriteLine(newJson);
validate(user.personal);
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment version: " + Environment.Version);
Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine();
try
{
TestClass.Test();
}
catch (Exception ex)
{
Console.WriteLine("Failed with unhandled exception: ");
Console.WriteLine(ex);
throw;
}
}
}
public class AssertionFailedException : System.Exception
{
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
}
public static class Assert
{
public static void IsTrue(bool value)
{
IsTrue(value, "failed");
}
public static void IsTrue(bool value, string message)
{
if (value == false)
throw new AssertionFailedException(message ?? "failed");
}
}