CSharp · Console
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Buffers;
using System.Text.Json;
using System.Text.Json.Serialization;
using NUnit.Framework; // Throws NUnit.Framework.AssertionException
//https://stackoverflow.com/questions/63376873/in-system-text-json-is-it-possible-to-specify-custom-indentation-rules
#nullable enable
public class NoIndentationConverter : NoIndentationConverter<object>
{
public override bool CanConvert(Type typeToConvert) => true;
}
public class NoIndentationConverter<T> : DefaultConverterFactory<T>
{
protected override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions modifiedOptions)
{
// TODO: investigate https://learn.microsoft.com/en-us/dotnet/api/microsoft.toolkit.highperformance.buffers.arraypoolbufferwriter-1
var bufferWriter = new ArrayBufferWriter<byte>();
using (var innerWriter = new Utf8JsonWriter(bufferWriter))
JsonSerializer.Serialize(innerWriter, value, modifiedOptions);
writer.WriteRawValue(bufferWriter.WrittenSpan, skipInputValidation : true);
}
protected override JsonSerializerOptions ModifyOptions(JsonSerializerOptions options) { (options = base.ModifyOptions(options)).WriteIndented = false; return options; }
}
public abstract class DefaultConverterFactory<T> : JsonConverterFactory
{
// Adapted from this answer https://stackoverflow.com/a/65430421/3744182
// To https://stackoverflow.com/questions/65430420/how-to-use-default-serialization-in-a-custom-system-text-json-jsonconverter
class DefaultConverter : JsonConverter<T>
{
readonly JsonSerializerOptions modifiedOptions;
readonly DefaultConverterFactory<T> factory;
public DefaultConverter(JsonSerializerOptions modifiedOptions, DefaultConverterFactory<T> factory) => (this.modifiedOptions, this.factory) = (modifiedOptions, factory);
public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) => factory.Write(writer, value, modifiedOptions);
public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => factory.Read(ref reader, typeToConvert, modifiedOptions);
public override bool CanConvert(Type typeToConvert) => typeof(T).IsAssignableFrom(typeToConvert);
}
protected virtual JsonSerializerOptions ModifyOptions(JsonSerializerOptions options)
=> options.CopyAndRemoveConverter(this.GetType());
protected virtual T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions modifiedOptions)
=> (T?)JsonSerializer.Deserialize(ref reader, typeToConvert, modifiedOptions);
protected virtual void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions modifiedOptions)
=> JsonSerializer.Serialize(writer, value, modifiedOptions);
public override bool CanConvert(Type typeToConvert) => typeof(T) == typeToConvert;
public sealed override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => new DefaultConverter(ModifyOptions(options), this);
}
public static class JsonSerializerExtensions
{
public static JsonSerializerOptions CopyAndRemoveConverter(this JsonSerializerOptions options, Type converterType)
{
var copy = new JsonSerializerOptions(options);
for (var i = copy.Converters.Count - 1; i >= 0; i--)
if (copy.Converters[i].GetType() == converterType)
copy.Converters.RemoveAt(i);
return copy;
}
}
public partial class Root
{
[JsonPropertyName("TILESET")]
public string Tileset { get; set; }
[JsonPropertyName("TILES")]
public Tiles Tiles { get; set; }
}
public partial class Tiles
{
[JsonPropertyName("TILE_1")]
public Tile1 Tile1 { get; set; }
}
public partial class Tile1
{
[JsonPropertyName("NAME")]
public string Name { get; set; }
[JsonPropertyName("TEXTURE_BOUNDS")]
[JsonConverter(typeof(NoIndentationConverter))]
public List<long> TextureBounds { get; set; }
[JsonPropertyName("SCREEN_BOUNDS")]
[JsonConverter(typeof(NoIndentationConverter))]
public List<long> ScreenBounds { get; set; }
}
class TestClass
{
public static void Test()
{
var originalJson = GetJson();
var options = new JsonSerializerOptions
{
WriteIndented = true,
};
var root = JsonSerializer.Deserialize<Root>(originalJson, options);
var json2 = JsonSerializer.Serialize(root, options);
Console.WriteLine("Serialized {0}: ", root);
Console.WriteLine(json2);
}
static string GetJson()
{
return @"{
""TILESET"": ""tilesets/HOW_TO_GET_TILESET_NAME_?"",
""TILES"": {
""TILE_1"": {
""NAME"": ""auto_tile_18"",
""TEXTURE_BOUNDS"": [
304,
16,
16,
16
],
""SCREEN_BOUNDS"": [
485,
159,
64,
64
]
}
}
}";
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine();
try
{
TestClass.Test();
}
catch (Exception ex)
{
Console.WriteLine("Failed with unhandled exception: ");
Console.WriteLine(ex);
throw;
}
}
}