Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small performance improvements #1636

Merged
merged 1 commit into from
Oct 30, 2023
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
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@
using NJsonSchema.Infrastructure;
using System.Runtime.Serialization;
using System.Reflection;
using NJsonSchema;
using NJsonSchema.Generation;
using System.Collections.Generic;

namespace NJsonSchema.NewtonsoftJson.Generation
{
/// <inheritdocs />
/// <inheritdoc />
public class NewtonsoftJsonReflectionService : ReflectionServiceBase<NewtonsoftJsonSchemaGeneratorSettings>
{
/// <inheritdocs />
/// <inheritdoc />
protected override JsonTypeDescription GetDescription(ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings,
Type originalType, bool isNullable, ReferenceTypeNullHandling defaultReferenceTypeNullHandling)
{
Expand All @@ -38,7 +36,7 @@ protected override JsonTypeDescription GetDescription(ContextualType contextualT
return base.GetDescription(contextualType, settings, originalType, isNullable, defaultReferenceTypeNullHandling);
}

/// <inheritdocs />
/// <inheritdoc />
public override bool IsNullable(ContextualType contextualType, ReferenceTypeNullHandling defaultReferenceTypeNullHandling)
{
var jsonPropertyAttribute = contextualType.GetContextAttribute<JsonPropertyAttribute>();
Expand All @@ -50,28 +48,27 @@ public override bool IsNullable(ContextualType contextualType, ReferenceTypeNull
return base.IsNullable(contextualType, defaultReferenceTypeNullHandling);
}

/// <inheritdocs />
/// <inheritdoc />
public override bool IsStringEnum(ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings)
{
var hasGlobalStringEnumConverter = settings.SerializerSettings?.Converters.OfType<StringEnumConverter>().Any() == true;
return hasGlobalStringEnumConverter || base.IsStringEnum(contextualType, settings);
}

/// <inheritdocs />
public override string ConvertEnumValue(object value, NewtonsoftJsonSchemaGeneratorSettings settings)

/// <inheritdoc />
public override Func<object, string?> GetEnumValueConverter(NewtonsoftJsonSchemaGeneratorSettings settings)
{
var converters = settings.SerializerSettings?.Converters.ToList() ?? new List<JsonConverter>();
var converters = settings.SerializerSettings.Converters.ToList();
if (!converters.OfType<StringEnumConverter>().Any())
{
converters.Add(new StringEnumConverter());
}

var json = JsonConvert.SerializeObject(value, Formatting.None, converters.ToArray());
var enumString = JsonConvert.DeserializeObject<string>(json)!;
return enumString;
return x => JsonConvert.DeserializeObject<string?>(JsonConvert.SerializeObject(x, Formatting.None, converters.ToArray()));
}

/// <inheritdocs />
/// <inheritdoc />
public override void GenerateProperties(JsonSchema schema, ContextualType contextualType, NewtonsoftJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
{
var contextualAccessors = contextualType
Expand Down Expand Up @@ -150,7 +147,7 @@ public override void GenerateProperties(JsonSchema schema, ContextualType contex
}
}

/// <inheritdocs />
/// <inheritdoc />
public override string GetPropertyName(ContextualAccessorInfo accessorInfo, JsonSchemaGeneratorSettings settings)
{
return GetPropertyName(null, accessorInfo, (NewtonsoftJsonSchemaGeneratorSettings)settings);
Expand Down Expand Up @@ -197,7 +194,7 @@ private void LoadPropertyOrField(JsonProperty jsonProperty, ContextualAccessorIn
}
}

private string GetPropertyName(JsonProperty? jsonProperty, ContextualAccessorInfo accessorInfo, NewtonsoftJsonSchemaGeneratorSettings settings)
private static string GetPropertyName(JsonProperty? jsonProperty, ContextualAccessorInfo accessorInfo, NewtonsoftJsonSchemaGeneratorSettings settings)
{
if (jsonProperty?.PropertyName != null)
{
Expand All @@ -208,8 +205,7 @@ private string GetPropertyName(JsonProperty? jsonProperty, ContextualAccessorInf
{
var propertyName = accessorInfo.GetName();

var contractResolver = settings.ActualContractResolver as DefaultContractResolver;
return contractResolver != null
return settings.ActualContractResolver is DefaultContractResolver contractResolver
? contractResolver.GetResolvedPropertyName(propertyName)
: propertyName;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace NJsonSchema.NewtonsoftJson.Generation
{
/// <inheritdocs />
/// <inheritdoc />
public class NewtonsoftJsonSchemaGeneratorSettings : JsonSchemaGeneratorSettings
{
private Dictionary<string, JsonContract?> _cachedContracts = new Dictionary<string, JsonContract?>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public JsonSchemaExtensionDataAttribute(string key, object value)
/// <summary>Gets the value.</summary>
public object Value { get; }

/// <inheritdocs />
/// <inheritdoc />
public IReadOnlyDictionary<string, object> ExtensionData => new Dictionary<string, object>
{
{ Key, Value }
Expand Down
5 changes: 2 additions & 3 deletions src/NJsonSchema/Generation/IReflectionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,11 @@ namespace NJsonSchema.Generation
public interface IReflectionService
{
/// <summary>
/// Converts an enum value to a JSON string.
/// Get converter that converts an enum value to a JSON string.
/// </summary>
/// <param name="value"></param>
/// <param name="settings"></param>
/// <returns></returns>
string ConvertEnumValue(object value, JsonSchemaGeneratorSettings settings);
Func<object, string?> GetEnumValueConverter(JsonSchemaGeneratorSettings settings);

/// <summary>
/// Gets the property name for the given accessor info.
Expand Down
12 changes: 7 additions & 5 deletions src/NJsonSchema/Generation/JsonSchemaGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;

namespace NJsonSchema.Generation
{
Expand Down Expand Up @@ -700,6 +701,7 @@ protected virtual void GenerateEnum(JsonSchema schema, JsonTypeDescription typeD
schema.EnumerationNames.Clear();
schema.IsFlagEnumerable = contextualType.GetInheritedAttribute<FlagsAttribute>() != null;

Func<object, string?>? enumValueConverter = null;
var underlyingType = Enum.GetUnderlyingType(contextualType.Type);
foreach (var enumName in Enum.GetNames(contextualType.Type))
{
Expand All @@ -711,16 +713,16 @@ protected virtual void GenerateEnum(JsonSchema schema, JsonTypeDescription typeD
else
{
// EnumMember only checked if StringEnumConverter is used
var attributes = contextualType.Type.GetRuntimeField(enumName)?.GetCustomAttributes();
dynamic? enumMemberAttribute = attributes?.FirstAssignableToTypeNameOrDefault("System.Runtime.Serialization.EnumMemberAttribute");
if (!string.IsNullOrEmpty(enumMemberAttribute?.Value))
var enumMemberAttribute = contextualType.Type.GetRuntimeField(enumName)?.GetCustomAttribute<EnumMemberAttribute>();
if (enumMemberAttribute != null && !string.IsNullOrEmpty(enumMemberAttribute.Value))
{
schema.Enumeration.Add((string)enumMemberAttribute!.Value);
schema.Enumeration.Add(enumMemberAttribute.Value);
}
else
{
enumValueConverter ??= Settings.ReflectionService.GetEnumValueConverter(Settings);
var value = Enum.Parse(contextualType.Type, enumName);
schema.Enumeration.Add(Settings.ReflectionService.ConvertEnumValue(value, Settings));
schema.Enumeration.Add(enumValueConverter(value));
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/NJsonSchema/Generation/ReflectionServiceBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ namespace NJsonSchema.Generation
public abstract class ReflectionServiceBase<TSettings> : IReflectionService
where TSettings : JsonSchemaGeneratorSettings
{
/// <inheritdocs />
public abstract string ConvertEnumValue(object value, TSettings settings);
/// <inheritdoc />
public abstract Func<object, string?> GetEnumValueConverter(TSettings settings);

/// <inheritdocs />
/// <inheritdoc />
public abstract void GenerateProperties(JsonSchema schema, ContextualType contextualType, TSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver);

/// <inheritdocs />
/// <inheritdoc />
public abstract string GetPropertyName(ContextualAccessorInfo accessorInfo, JsonSchemaGeneratorSettings settings);

/// <summary>Creates a <see cref="JsonTypeDescription"/> from a <see cref="Type"/>. </summary>
Expand Down Expand Up @@ -368,9 +368,9 @@ bool IReflectionService.IsStringEnum(ContextualType contextualType, JsonSchemaGe
return IsStringEnum(contextualType, (TSettings)settings);
}

string IReflectionService.ConvertEnumValue(object value, JsonSchemaGeneratorSettings settings)
Func<object, string?> IReflectionService.GetEnumValueConverter(JsonSchemaGeneratorSettings settings)
{
return ConvertEnumValue(value, (TSettings)settings);
return GetEnumValueConverter((TSettings)settings);
}

void IReflectionService.GenerateProperties(JsonSchema schema, ContextualType contextualType, JsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
Expand Down
32 changes: 13 additions & 19 deletions src/NJsonSchema/Generation/SystemTextJsonReflectionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,16 @@

namespace NJsonSchema.Generation
{
/// <inheritdocs />
/// <inheritdoc />
public class SystemTextJsonReflectionService : ReflectionServiceBase<SystemTextJsonSchemaGeneratorSettings>
{
/// <inheritdocs />
/// <inheritdoc />
public override void GenerateProperties(JsonSchema schema, ContextualType contextualType, SystemTextJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver)
{
foreach (var accessorInfo in contextualType
.Properties
.OfType<ContextualAccessorInfo>()
.Concat(contextualType.Fields)
.Where(p => p.MemberInfo.DeclaringType == contextualType.Type))
foreach (var accessorInfo in contextualType.Properties.OfType<ContextualAccessorInfo>().Concat(contextualType.Fields))
{
if (accessorInfo.MemberInfo is FieldInfo fieldInfo &&
(fieldInfo.IsPrivate || fieldInfo.IsStatic || !fieldInfo.IsDefined(typeof(DataMemberAttribute))))
if (accessorInfo.MemberInfo.DeclaringType != contextualType.Type ||
(accessorInfo.MemberInfo is FieldInfo fieldInfo && (fieldInfo.IsPrivate || fieldInfo.IsStatic || !fieldInfo.IsDefined(typeof(DataMemberAttribute)))))
{
continue;
}
Expand Down Expand Up @@ -70,7 +66,7 @@ public override void GenerateProperties(JsonSchema schema, ContextualType contex

if (!ignored)
{
var propertyTypeDescription = ((IReflectionService)this).GetDescription(accessorInfo.AccessorType, settings);
var propertyTypeDescription = GetDescription(accessorInfo.AccessorType, settings.DefaultReferenceTypeNullHandling, settings);
var propertyName = GetPropertyName(accessorInfo, settings);

var propertyAlreadyExists = schema.Properties.ContainsKey(propertyName);
Expand All @@ -82,7 +78,7 @@ public override void GenerateProperties(JsonSchema schema, ContextualType contex
}
else
{
throw new InvalidOperationException("The JSON property '" + propertyName + "' is defined multiple times on type '" + contextualType.Type.FullName + "'.");
throw new InvalidOperationException($"The JSON property '{propertyName}' is defined multiple times on type '{contextualType.Type.FullName}'.");
}
}

Expand All @@ -104,17 +100,16 @@ public override void GenerateProperties(JsonSchema schema, ContextualType contex
}
}

/// <inheritdocs />
/// <inheritdoc />
public override bool IsStringEnum(ContextualType contextualType, SystemTextJsonSchemaGeneratorSettings settings)
{
var hasGlobalStringEnumConverter = settings.SerializerOptions.Converters.OfType<JsonStringEnumConverter>().Any();
return hasGlobalStringEnumConverter || base.IsStringEnum(contextualType, settings);
}

/// <inheritdocs />
public override string ConvertEnumValue(object value, SystemTextJsonSchemaGeneratorSettings settings)
/// <inheritdoc />
public override Func<object, string?> GetEnumValueConverter(SystemTextJsonSchemaGeneratorSettings settings)
{
// TODO(performance): How to improve this one here?
var serializerOptions = new JsonSerializerOptions();
foreach (var converter in settings.SerializerOptions.Converters)
{
Expand All @@ -126,17 +121,16 @@ public override string ConvertEnumValue(object value, SystemTextJsonSchemaGenera
serializerOptions.Converters.Add(new JsonStringEnumConverter());
}

var json = JsonSerializer.Serialize(value, value.GetType(), serializerOptions);
return JsonSerializer.Deserialize<string>(json)!;
return x => JsonSerializer.Deserialize<string?>(JsonSerializer.Serialize(x, x.GetType(), serializerOptions));
}

/// <inheritdocs />
/// <inheritdoc />
public override string GetPropertyName(ContextualAccessorInfo accessorInfo, JsonSchemaGeneratorSettings settings)
{
return GetPropertyName(accessorInfo, (SystemTextJsonSchemaGeneratorSettings)settings);
}

private string GetPropertyName(ContextualAccessorInfo accessorInfo, SystemTextJsonSchemaGeneratorSettings settings)
private static string GetPropertyName(ContextualAccessorInfo accessorInfo, SystemTextJsonSchemaGeneratorSettings settings)
{
dynamic? jsonPropertyNameAttribute = accessorInfo.ContextAttributes
.FirstAssignableToTypeNameOrDefault("System.Text.Json.Serialization.JsonPropertyNameAttribute", TypeNameStyle.FullName);
Expand Down
2 changes: 1 addition & 1 deletion src/NJsonSchema/JsonPathUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private static bool FindJsonPaths(object obj, Dictionary<object, string?> search
if (searchedObjects.ContainsKey(obj))
{
searchedObjects[obj] = basePath;
if (searchedObjects.All(p => p.Value != null))
if (searchedObjects.All(static p => p.Value != null))
{
return true;
}
Expand Down
Loading
Loading