Last active
December 20, 2022 10:59
-
-
Save fliedonion/6a0dc56220813473181f7f19b4efc1c4 to your computer and use it in GitHub Desktop.
JSON.NET Deserialize null string to string.Empty.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using JsonConvertOptionForm.Entity; | |
using Newtonsoft.Json; | |
using Newtonsoft.Json.Linq; | |
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Data; | |
using System.Diagnostics; | |
using System.Drawing; | |
using System.IO; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows.Forms; | |
namespace JsonConvertOptionForm | |
{ | |
public partial class SampleCodeForm : Form | |
{ | |
public SampleCodeForm() | |
{ | |
InitializeComponent(); | |
} | |
// Add two buttons in the designer. | |
private void writeTestJsonButton_Click(object sender, EventArgs e) | |
{ | |
var x = new SomeEntity | |
{ | |
Number = 10, | |
// Text = "TextProp" + new string('X', 1024 * 1024 * 30), // 30MB // 30MBでもexistingValue 引数はセットされなかった。 | |
// The existingValue argument was not set even at 30 MB. | |
Text = "TextProp", | |
TextNull = null, | |
Products = new List<string> { "l1", "l2", null }, | |
Dic = new Dictionary<string, int> { { "abc", 100 }, { "efg", 100 } }, | |
Nested = new List<List<string>>{ | |
new List<string> { "1-1", "1-2" }, | |
new List<string> { "2-1", null, "2-3" }, | |
}, | |
UpdateDate = DateTime.Now, | |
UpdateDates = new List<DateTime> { DateTime.Now, DateTime.Now, } | |
}; | |
var json = Newtonsoft.Json.JsonConvert.SerializeObject(x, Newtonsoft.Json.Formatting.Indented); | |
File.WriteAllText("sample.json", json, new UTF8Encoding(false)); | |
} | |
private void readJsonTestButton_Click(object sender, EventArgs e) | |
{ | |
var json =File.ReadAllText("sample.json", new UTF8Encoding(false)); | |
{ | |
var defaultDeserialize = Newtonsoft.Json.JsonConvert.DeserializeObject<SomeEntity>(json); | |
Debug.Print("-- with default converter ------------------------"); | |
Debug.Print(defaultDeserialize.Text.Length.ToString()); | |
Debug.Print(defaultDeserialize.TextNull ?? "<null>"); | |
Debug.Print(defaultDeserialize.Number.ToString() + " " + defaultDeserialize.Number.GetType()); | |
Debug.Print(defaultDeserialize.Products[2] ?? "<null>"); | |
Debug.Print(defaultDeserialize.Nested[1][1] ?? "<null>"); | |
Debug.Print($"'{defaultDeserialize.Products[2] ?? "<null>"}' is null {defaultDeserialize.Products[2] == null} : JSON上のnullアイテム が null かどうか。expect true"); | |
Debug.Print($"'{defaultDeserialize.Nested[1][1] ?? "<null>"}' is null {defaultDeserialize.Nested[1][1] == null} : JSON上のnullアイテム が null かどうか。expect true"); | |
Debug.Print($"'{defaultDeserialize.Products[1]}' is NOT null {defaultDeserialize.Products[1] != null} : JSON上の非nullアイテムもちゃんと取れていることの確認"); | |
Debug.Print($"'{defaultDeserialize.Nested[1][2]}' is NOT null {defaultDeserialize.Nested[1][2] != null} : JSON上の非nullアイテムもちゃんと取れていることの確認"); | |
} | |
{ | |
var desNumText = JsonConvert.DeserializeObject<SomeEntityWithNumberAsText>(json, new NullToEmptyForStringTypeDeserializeConverter()); | |
Debug.Print("-- with my StringConverter ------------------------"); | |
Debug.Print(desNumText.Text.Length.ToString()); | |
Debug.Print(desNumText.TextNull ?? "<null>"); | |
Debug.Print((desNumText.Number ?? "<null>") + " " + desNumText.Number.GetType() + ": シリアル化(JSON)時点では数値オブジェクト、デシリアライズで文字列プロパティで受け付けたとき。"); | |
Debug.Print(desNumText.Products[2] ?? "<null>"); | |
Debug.Print(desNumText.Nested[1][1] ?? "<null>"); | |
Debug.Print($"'{desNumText.Products[2] ?? "<null>"}' is null {desNumText.Products[2] == null} : JSON上のnullアイテム が null かどうか。expect false"); | |
Debug.Print($"'{desNumText.Nested[1][1] ?? "<null>"}' is null {desNumText.Nested[1][1] == null} : JSON上のnullアイテム が null かどうか。expect false"); | |
Debug.Print($"'{desNumText.Products[1]}' is not null {desNumText.Products[1] != null} : JSON上の非nullアイテムもちゃんと取れていることの確認"); | |
Debug.Print($"'{desNumText.Nested[1][2]}' is not null {desNumText.Nested[1][2] != null} : JSON上の非nullアイテムもちゃんと取れていることの確認"); | |
Debug.Print("finish desealize"); | |
} | |
// if you want to use settings. you can specify Converter like following. | |
var settings = new JsonSerializerSettings | |
{ | |
Converters = new List<JsonConverter> { new NullToEmptyForStringTypeDeserializeConverter(), new NullToEmptyForStringTypeDeserializeConverter() } | |
}; | |
} | |
public class NullToEmptyForStringTypeDeserializeConverter : JsonConverter<String> | |
{ | |
// when CanWrite == false, use this only for deserialize. | |
public override bool CanWrite => false; | |
public override void WriteJson(JsonWriter writer, String value, JsonSerializer serializer) | |
{ | |
throw new NotImplementedException("Not Support for Serialize"); | |
} | |
public override String ReadJson(JsonReader reader, Type objectType, String existingValue, bool hasExistingValue, JsonSerializer serializer) | |
{ | |
if (hasExistingValue) throw new JsonSerializationException($"{nameof(NullToEmptyForStringTypeDeserializeConverter)} does not support desealize with existingValue."); | |
if (reader.Value != null && reader.ValueType != typeof(String)) { | |
// TODO: さらに複雑には別のConverterを呼んだ方が良いのかもしれないが、未検証。(間違えるとConverter同士が呼びあい無限ループの可能性もあるのでハンドル済みCOnverterが持てるオーバーロード作るとか工夫しないとだめかも) | |
// TODO: For more complexity, it may be better to call another Converter, but this has not been tested. (If you make a mistake, there is a possibility that converters will call each other, resulting in an infinite loop, so you may need to create an overload that allows handled COnverters to have their own handles.) | |
// | |
// if (serializer.Converters.Count > 0) | |
// { | |
// foreach (var conv in serializer.Converters) | |
// { | |
// if (!ReferenceEquals(this, conv) && conv.CanRead && conv.CanConvert(objectType)) | |
// { | |
// return conv.ReadJson(reader, objectType, existingValue, serializer) as string; | |
// } | |
// } | |
// } | |
// 他の型である場合は、JObjectに任せる。 | |
var token = JObject.ReadFrom(reader); | |
return token.ToObject<String>(); | |
} | |
string s = (string)reader.Value ?? ""; | |
return s; | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace JsonConvertOptionForm.Entity | |
{ | |
public class SomeEntity | |
{ | |
public int Number { get; set; } | |
public string Text { get; set; } | |
public string TextNull { get; set; } | |
public List<string> Products { get; set; } | |
public Dictionary<string, int> Dic { get; set; } | |
public List<List<string>> Nested { get; set; } | |
public DateTime UpdateDate; | |
public List<DateTime> UpdateDates; | |
} | |
public class SomeEntityWithNumberAsText | |
{ | |
public string Number { get; set; } | |
public string Text { get; set; } | |
public string TextNull { get; set; } | |
public List<string> Products { get; set; } | |
public Dictionary<string, int> Dic { get; set; } | |
public List<List<string>> Nested { get; set; } | |
public DateTime UpdateDate; | |
public List<DateTime> UpdateDates; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment