[Fork] .NET 6 [Fork] [Fork] https://stackoverflow.com/questions/63376873/in-system-text-json-is-it-possible-to-specify-custom-indentation-rules

CSharp · Console

/Program.cs

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")]
        public List<long> TextureBounds { get; set; }

        [JsonPropertyName("SCREEN_BOUNDS")]
        public List<long> ScreenBounds { get; set; }
    }

    class TestClass
    {
        public static void Test()
        {
			var originalJson = GetJson();
			
			var options = new JsonSerializerOptions
			{
				Converters = { new NoIndentationConverter<List<long>>() },
				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;
			}
		}
	}
;