Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,300 +1,85 @@
#nullable enable
using System;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace JsonSubTypes.Aot.Generated
{
/// <summary>Generated by JsonSubTypes.Aot. Compiled converter for global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget.</summary>
public sealed class DottedGadgetJsonSubTypesConverter : JsonConverter<global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget>
public sealed class DottedGadgetJsonSubTypesConverter : JsonSubTypesAotValueConverterBase<global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget>
{
public override bool CanConvert(Type typeToConvert) => typeToConvert == typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget);
private const string DiscriminatorPropertyNameValue = "nested.type";
protected override string DiscriminatorPropertyName => DiscriminatorPropertyNameValue;

public override void Write(Utf8JsonWriter writer, global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget value, JsonSerializerOptions options)
protected override System.Collections.Generic.Dictionary<System.Type, System.Action<Utf8JsonWriter, JsonSerializerOptions>> DiscriminatorWriters { get; } = new System.Collections.Generic.Dictionary<System.Type, System.Action<Utf8JsonWriter, JsonSerializerOptions>>
{
if (value is null)
{
writer.WriteNullValue();
return;
}
Type runtimeType = value.GetType();
string payload;
if (runtimeType == typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget))
{
if (IsRegistered(runtimeType))
{
payload = SerializeBasePayload((global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget)value, options);
}
else
{
WriteBaseObject(writer, (global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget)value, options);
return;
}
}
else if (IsRegistered(runtimeType))
{
payload = JsonSerializer.Serialize(value, options.GetTypeInfo(runtimeType));
}
else if (TryWriteNestedObject(writer, value, runtimeType, options))
{
return;
}
else if (TryWriteDynamic(writer, value, runtimeType, options))
[typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedElectronic)] = static (writer, options) => writer.WriteStringValue("electronic")
};

protected override Type SelectType(JsonElement root, JsonSerializerOptions options)
{
if (!TryGetValueInJson(root, DiscriminatorPropertyNameValue, options, out JsonElement discriminator))
{
return;
return typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget);
}
else
Type? staticType = ResolveStaticType(discriminator);
if (staticType != null)
{
JsonSerializer.Serialize(writer, value, options.GetTypeInfo(runtimeType));
return;
return staticType;
}
using JsonDocument payloadDocument = JsonDocument.Parse(payload);
string discriminatorName = "nested.type";
if (options.PropertyNamingPolicy != null)
if (TryGetDynamicType(discriminator, out Type? dynamicType))
{
discriminatorName = options.PropertyNamingPolicy.ConvertName(discriminatorName);
return dynamicType!;
}
writer.WriteStartObject();
writer.WritePropertyName(discriminatorName);
WriteDiscriminatorValue(writer, runtimeType, options);
foreach (JsonProperty property in payloadDocument.RootElement.EnumerateObject())
if (CustomTypeNameResolver is not null)
{
if (!property.NameEquals(discriminatorName))
Type? customType = CustomTypeNameResolver(GetDiscriminatorKey(discriminator));
if (customType != null)
{
property.WriteTo(writer);
return customType;
}
}
writer.WriteEndObject();
return typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget);
}

public override global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
private static Type? ResolveStaticType(JsonElement discriminator)
{
if (reader.TokenType == JsonTokenType.Null)
{
return null;
}
if (reader.TokenType != JsonTokenType.StartObject)
{
throw new JsonException("Unrecognized token: " + reader.TokenType);
}
using JsonDocument document = JsonDocument.ParseValue(ref reader);
JsonElement root = document.RootElement;
Type target = SelectType(root, options);
if (target == typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget))
switch (discriminator.ValueKind)
{
return DeserializeBase(root, options);
}
return (global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget?)JsonSerializer.Deserialize(root.GetRawText(), options.GetTypeInfo(target));
}

private Type SelectType(JsonElement root, JsonSerializerOptions options)
{
if (TryGetValueInJson(root, "nested.type", options, out JsonElement discriminator))
{

if (discriminator.ValueKind == JsonValueKind.String)
{
switch (discriminator.GetString())
{
case JsonValueKind.String:
switch (discriminator.GetString())
{
case "electronic": return typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedElectronic);
}
}

if (TryGetDynamicType(discriminator, out Type? dynamicType))
{
return dynamicType!;
}
if (CustomTypeNameResolver is not null)
{
Type? customType = CustomTypeNameResolver(GetDiscriminatorKey(discriminator));
if (customType != null)
{
return customType;
}
break;
}
return null;
}
return typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget);
}
return typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget);
}

private static readonly System.Collections.Generic.Dictionary<System.Type, System.Action<Utf8JsonWriter, JsonSerializerOptions>> DiscriminatorWriters = new System.Collections.Generic.Dictionary<System.Type, System.Action<Utf8JsonWriter, JsonSerializerOptions>>
{
[typeof(global::JsonSubTypes.Aot.Generated.TestDomain.DottedElectronic)] = static (writer, options) => writer.WriteStringValue("electronic")
};

private static bool IsRegistered(Type runtimeType)
{
return DiscriminatorWriters.ContainsKey(runtimeType);
}

private static void WriteDiscriminatorValue(Utf8JsonWriter writer, Type runtimeType, JsonSerializerOptions options)
{
if (DiscriminatorWriters.TryGetValue(runtimeType, out System.Action<Utf8JsonWriter, JsonSerializerOptions>? write))
{
write(writer, options);
return;
}
throw new JsonException("Impossible to serialize type: " + runtimeType.FullName + " because there is no registered mapping for the discriminator property");
}

public readonly System.Collections.Concurrent.ConcurrentDictionary<object, Type> DynamicSubtypes = new System.Collections.Concurrent.ConcurrentDictionary<object, Type>();
private readonly System.Collections.Concurrent.ConcurrentDictionary<Type, object> _dynamicReverse = new System.Collections.Concurrent.ConcurrentDictionary<Type, object>();

public void RegisterDynamicSubtype(object discriminator, Type type)
{
DynamicSubtypes[discriminator] = type;
_dynamicReverse[type] = discriminator; // last registration wins, like the builder
}

/// <summary>
/// Custom discriminator-to-type resolution hook, invoked after the static
/// registrations and DynamicSubtypes. Assign it to implement your own
/// name-based lookup (e.g. assembly scanning, a DI registry). The resolved
/// type must be resolvable by the TypeInfoResolver (in the source-gen context
/// for Native AOT).
/// </summary>
public Func<object?, Type?>? CustomTypeNameResolver { get; set; }

private static object? GetDiscriminatorKey(JsonElement discriminator)
{
switch (discriminator.ValueKind)
{
case JsonValueKind.String:
return discriminator.GetString();
case JsonValueKind.Number when int.TryParse(discriminator.GetRawText(), out int keyInt):
return keyInt;
default:
return discriminator.GetRawText();
}
}

private bool TryGetDynamicType(JsonElement discriminator, out Type? dynamicType)
{
switch (discriminator.ValueKind)
{
case JsonValueKind.String:
return DynamicSubtypes.TryGetValue(discriminator.GetString()!, out dynamicType);
case JsonValueKind.Number:
if (int.TryParse(discriminator.GetRawText(), out int dynamicInt) && DynamicSubtypes.TryGetValue(dynamicInt, out dynamicType))
{
return true;
}
return DynamicSubtypes.TryGetValue(discriminator.GetRawText(), out dynamicType);
default:
return DynamicSubtypes.TryGetValue(discriminator.GetRawText(), out dynamicType);
}
}

private static bool TryWriteNestedObject(Utf8JsonWriter writer, global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget value, Type runtimeType, JsonSerializerOptions options)
{

return false;
}

private bool TryWriteDynamic(Utf8JsonWriter writer, global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget value, Type runtimeType, JsonSerializerOptions options)
{
if (_dynamicReverse.TryGetValue(runtimeType, out object? dynamicDiscriminator))
protected override void WriteBaseObject(Utf8JsonWriter writer, global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget value, JsonSerializerOptions options)
{
writer.WriteStartObject();
string dynamicDiscriminatorName = "nested.type";
if (options.PropertyNamingPolicy != null)
{
dynamicDiscriminatorName = options.PropertyNamingPolicy.ConvertName(dynamicDiscriminatorName);
}
writer.WritePropertyName(dynamicDiscriminatorName);
writer.WriteRawValue(JsonSerializer.Serialize(dynamicDiscriminator, options.GetTypeInfo(dynamicDiscriminator.GetType())));
string payload = JsonSerializer.Serialize(value, options.GetTypeInfo(runtimeType));
using JsonDocument payloadDocument = JsonDocument.Parse(payload);
foreach (JsonProperty property in payloadDocument.RootElement.EnumerateObject())
{
property.WriteTo(writer);
}
writer.WriteEndObject();
return true;
}
return false;
}
private static string SerializeBasePayload(global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget value, JsonSerializerOptions options)
{
using System.IO.MemoryStream stream = new System.IO.MemoryStream();
using (Utf8JsonWriter writer = new Utf8JsonWriter(stream))
{
WriteBaseObject(writer, value, options);
}
return System.Text.Encoding.UTF8.GetString(stream.ToArray());
}

private static void WriteBaseObject(Utf8JsonWriter writer, global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget value, JsonSerializerOptions options)
{
writer.WriteStartObject();
string nameAge = "Age";
if (options.PropertyNamingPolicy != null && true)
{
nameAge = options.PropertyNamingPolicy.ConvertName(nameAge);
}
writer.WritePropertyName(nameAge);
JsonSerializer.Serialize(writer, value.Age, options.GetTypeInfo(typeof(int)));
writer.WriteEndObject();
}

private static global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget DeserializeBase(JsonElement root, JsonSerializerOptions options)
{
global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget instance = new global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget();
writer.WriteEndObject();
}
protected override global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget DeserializeBase(JsonElement root, JsonSerializerOptions options)
{
global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget instance = new global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget();
if (TryGetProperty(root, "Age", options, out JsonElement AgeValue))
{
instance.Age = (int)JsonSerializer.Deserialize(AgeValue.GetRawText(), options.GetTypeInfo(typeof(int)))!;
}
return instance;
}

private static bool TryGetProperty(JsonElement root, string name, JsonSerializerOptions options, out JsonElement value)
{
if (root.TryGetProperty(name, out value))
{
return true;
}
string? convertedName = options.PropertyNamingPolicy?.ConvertName(name);
if (convertedName != null && convertedName != name && root.TryGetProperty(convertedName, out value))
{
return true;
}
if (options.PropertyNameCaseInsensitive)
{
foreach (JsonProperty property in root.EnumerateObject())
{
if (string.Equals(property.Name, name, StringComparison.OrdinalIgnoreCase))
{
value = property.Value;
return true;
}
}
}
return false;
}

private static bool TryGetValueInJson(JsonElement root, string propertyName, JsonSerializerOptions options, out JsonElement value)
{
if (TryGetProperty(root, propertyName, options, out value))
{
return true;
return instance;
}
if (propertyName.IndexOf('.') >= 0)
protected override bool TryWriteNestedObject(Utf8JsonWriter writer, global::JsonSubTypes.Aot.Generated.TestDomain.DottedGadget value, Type runtimeType, JsonSerializerOptions options)
{
string[] segments = propertyName.Split('.');
JsonElement current = root;
foreach (string segment in segments)
{
if (!TryGetProperty(current, segment, options, out current))
{
value = default;
return false;
}
}
value = current;
return true;
return false;
}
return false;
}
}
}
Loading
Loading