Using System.Text.Json source generation in my application isn't providing for size reductions in the app because all the JsonConverters are still being rooted in the app.
Repro
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
using ConsoleApp13;
using ConsoleApp13.JsonSourceGeneration;
[assembly: JsonSerializable(typeof(WeatherForecast))]
namespace ConsoleApp13
{
class Program
{
static void Main(string[] args)
{
string f = @"{""TemperatureC"":0,""Summary"":""hi""}";
var forecast = JsonSerializer.Deserialize(f, new JsonContext().WeatherForecast);
Console.WriteLine(forecast);
}
}
public record WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public string Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
dotnet publish -r win-x64 -c Release -p:PublishTrimmed=true -p:DebuggerSupport=false
View the outputted assemblies, and notice that System.Text.Json.dll is ~289KB, it still has all its JsonConverters in it, and System.Collections.Immutable.dll is in my app, even though I don't use it.
Analysis
From looking at the results, the reason everything is still rooted is because of the following call graph:

This is what is rooting ObjectConverter. Then inside ObjectConverter.Read, it uses JsonNodeConverter.Instance:
|
public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) |
|
{ |
|
if (options.UnknownTypeHandling == JsonUnknownTypeHandling.JsonElement) |
|
{ |
|
return JsonElement.ParseValue(ref reader); |
|
} |
|
|
|
return JsonNodeConverter.Instance.Read(ref reader, typeToConvert, options); |
This brings in all of the JsonNode hierarchy, including JsonValue<T>, which overrides ToString() to call JsonSerializer.Serialize without source gen information:
|
JsonSerializer.Serialize(writer, _value, _value!.GetType(), options); |
That this point, since JsonSerializer.Serialize is called without source gen information, it now roots all JsonConverters, and the size of the app grows by a lot.
cc @layomia @steveharter @marek-safar @vitek-karas @CoffeeFlux
Using System.Text.Json source generation in my application isn't providing for size reductions in the app because all the JsonConverters are still being rooted in the app.
Repro
dotnet publish -r win-x64 -c Release -p:PublishTrimmed=true -p:DebuggerSupport=falseView the outputted assemblies, and notice that
System.Text.Json.dllis ~289KB, it still has all its JsonConverters in it, andSystem.Collections.Immutable.dllis in my app, even though I don't use it.Analysis
From looking at the results, the reason everything is still rooted is because of the following call graph:
This is what is rooting
ObjectConverter. Then insideObjectConverter.Read, it usesJsonNodeConverter.Instance:runtime/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/ObjectConverter.cs
Lines 15 to 22 in b4f4418
This brings in all of the
JsonNodehierarchy, includingJsonValue<T>, which overridesToString()to callJsonSerializer.Serializewithout source gen information:runtime/src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonValueOfT.cs
Line 89 in 1410c12
That this point, since
JsonSerializer.Serializeis called without source gen information, it now roots all JsonConverters, and the size of the app grows by a lot.cc @layomia @steveharter @marek-safar @vitek-karas @CoffeeFlux