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

Added setting UsePolymorphicSerialization #462

Merged
merged 5 commits into from
Sep 11, 2024
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
97 changes: 74 additions & 23 deletions src/Refitter.Core/CSharpClientGeneratorFactory.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Reflection;
using NJsonSchema.CodeGeneration;
using NJsonSchema.CodeGeneration.CSharp;

using NSwag;
Expand All @@ -17,30 +19,41 @@
}
}

var csharpClientGeneratorSettings = new CSharpClientGeneratorSettings
{
GenerateClientClasses = false,
GenerateDtoTypes = true,
GenerateClientInterfaces = false,
GenerateExceptionClasses = false,
CodeGeneratorSettings = { PropertyNameGenerator = new CustomCSharpPropertyNameGenerator(), },
CSharpGeneratorSettings =
{
Namespace = settings.ContractsNamespace ?? settings.Namespace,
JsonLibrary = CSharpJsonLibrary.SystemTextJson,
TypeAccessModifier = settings.TypeAccessibility.ToString().ToLowerInvariant(),
ClassStyle =
settings.ImmutableRecords ||
settings.CodeGeneratorSettings?.GenerateNativeRecords is true
? CSharpClassStyle.Record
: CSharpClassStyle.Poco,
GenerateNativeRecords =
settings.ImmutableRecords ||
settings.CodeGeneratorSettings?.GenerateNativeRecords is true,
}
};

Check warning on line 44 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L44

Added line #L44 was not covered by tests
csharpClientGeneratorSettings.CSharpGeneratorSettings.TemplateFactory = new CustomTemplateFactory(
csharpClientGeneratorSettings.CSharpGeneratorSettings,
[
typeof(CSharpGenerator).Assembly,
typeof(CSharpGeneratorBaseSettings).Assembly,
typeof(CustomTemplateFactory).Assembly,
]);

var generator = new CustomCSharpClientGenerator(
document,
new CSharpClientGeneratorSettings
{
GenerateClientClasses = false,
GenerateDtoTypes = true,
GenerateClientInterfaces = false,
GenerateExceptionClasses = false,
CodeGeneratorSettings = { PropertyNameGenerator = new CustomCSharpPropertyNameGenerator(), },
CSharpGeneratorSettings =
{
Namespace = settings.ContractsNamespace ?? settings.Namespace,
JsonLibrary = CSharpJsonLibrary.SystemTextJson,
TypeAccessModifier = settings.TypeAccessibility.ToString().ToLowerInvariant(),
ClassStyle =
settings.ImmutableRecords ||
settings.CodeGeneratorSettings?.GenerateNativeRecords is true
? CSharpClassStyle.Record
: CSharpClassStyle.Poco,
GenerateNativeRecords =
settings.ImmutableRecords ||
settings.CodeGeneratorSettings?.GenerateNativeRecords is true,
}
});
csharpClientGeneratorSettings,
settings.UsePolymorphicSerialization);

MapCSharpGeneratorSettings(
settings.CodeGeneratorSettings,
Expand Down Expand Up @@ -82,4 +95,42 @@
settingsProperty.SetValue(destination, value);
}
}
}

Check warning on line 98 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L98

Added line #L98 was not covered by tests
/// <summary>
/// custom template factory

Check warning on line 100 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L100

Added line #L100 was not covered by tests
/// solely for the purpose of supporting UsePolymorphicSerialization
/// This class and its templates should be removed when NSwag supports this feature.

Check warning on line 102 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L102

Added line #L102 was not covered by tests
/// </summary>
private class CustomTemplateFactory : NSwag.CodeGeneration.DefaultTemplateFactory
{
/// <summary>Initializes a new instance of the <see cref="DefaultTemplateFactory" /> class.</summary>
/// <param name="settings">The settings.</param>

Check warning on line 107 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L105-L107

Added lines #L105 - L107 were not covered by tests
/// <param name="assemblies">The assemblies.</param>
public CustomTemplateFactory(CodeGeneratorSettingsBase settings, Assembly[] assemblies)
: base(settings, assemblies)
{
}

Check warning on line 113 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L113

Added line #L113 was not covered by tests
/// <summary>Tries to load an embedded Liquid template.</summary>
/// <param name="language">The language.</param>

Check warning on line 115 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L115

Added line #L115 was not covered by tests
/// <param name="template">The template name.</param>
/// <returns>The template.</returns>

Check warning on line 117 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L117

Added line #L117 was not covered by tests
protected override string GetEmbeddedLiquidTemplate(string language, string template)
{

Check warning on line 119 in src/Refitter.Core/CSharpClientGeneratorFactory.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CSharpClientGeneratorFactory.cs#L119

Added line #L119 was not covered by tests
template = template.TrimEnd('!');
var assembly = Assembly.GetExecutingAssembly(); // this code is running in Refitter.Core and Refitter.SourceGenerator
var resourceName = $"{assembly.GetName().Name}.Templates.{template}.liquid";

var resource = assembly.GetManifestResourceStream(resourceName);
if (resource != null)
{
using (var reader = new StreamReader(resource))
{
return reader.ReadToEnd();
}
}

return base.GetEmbeddedLiquidTemplate(language, template);
}
}
}
133 changes: 128 additions & 5 deletions src/Refitter.Core/CustomCSharpClientGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,139 @@
using NJsonSchema;
using NJsonSchema.CodeGeneration;
using NJsonSchema.CodeGeneration.CSharp;
using NJsonSchema.CodeGeneration.CSharp.Models;
using NSwag;
using NSwag.CodeGeneration.CSharp;
using NSwag.CodeGeneration.CSharp.Models;

namespace Refitter.Core;

internal class CustomCSharpClientGenerator : CSharpClientGenerator
internal class CustomCSharpClientGenerator(OpenApiDocument document, CSharpClientGeneratorSettings settings, bool usePolymorphicSerialization)
#pragma warning disable CS9107 // Parameter is captured into the state of the enclosing type and its value is also passed to the base constructor. The value might be captured by the base class as well.
: CSharpClientGenerator(document, settings)
#pragma warning restore CS9107 // Parameter is captured into the state of the enclosing type and its value is also passed to the base constructor. The value might be captured by the base class as well.
{
internal CustomCSharpClientGenerator(OpenApiDocument document, CSharpClientGeneratorSettings settings)
: base(document, settings)
internal CSharpOperationModel CreateOperationModel(OpenApiOperation operation) =>
CreateOperationModel(operation, Settings);

/// <summary>
/// override to generate DTO types with our custom CSharpGenerator
/// This code should be removed when NSwag supports STJ polymorphic serialization
/// </summary>

Check warning on line 22 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L22

Added line #L22 was not covered by tests
protected override IEnumerable<CodeArtifact> GenerateDtoTypes()
{
var generator = new CCustomSharpGenerator(document, Settings.CSharpGeneratorSettings, (CSharpTypeResolver)Resolver, usePolymorphicSerialization);
return generator.GenerateTypes();
}

internal CSharpOperationModel CreateOperationModel(OpenApiOperation operation) =>
CreateOperationModel(operation, Settings);
private class CCustomSharpGenerator(OpenApiDocument document, CSharpGeneratorSettings settings, CSharpTypeResolver resolver, bool usePolymorphicSerialization)
#pragma warning disable CS9107 // Parameter is captured into the state of the enclosing type and its value is also passed to the base constructor. The value might be captured by the base class as well.

Check warning on line 30 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L30

Added line #L30 was not covered by tests
: CSharpGenerator(document, settings, resolver)
#pragma warning restore CS9107 // Parameter is captured into the state of the enclosing type and its value is also passed to the base constructor. The value might be captured by the base class as well.

Check warning on line 32 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L32

Added line #L32 was not covered by tests
{
/// <summary>
/// override to generate Class with our custom ClassTemplateModel
/// code is taken from NJsonSchema.CodeGeneration.CSharp.CSharpGenerator.GenerateType

Check warning on line 36 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L35-L36

Added lines #L35 - L36 were not covered by tests
/// </summary>
protected override CodeArtifact GenerateType(JsonSchema schema, string typeNameHint)
{

Check warning on line 39 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L38-L39

Added lines #L38 - L39 were not covered by tests
var typeName = resolver.GetOrGenerateTypeName(schema, typeNameHint);

Check warning on line 41 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L41

Added line #L41 was not covered by tests
if (schema.IsEnumeration)
{
return base.GenerateType(schema, typeName);
}

Check warning on line 45 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L45

Added line #L45 was not covered by tests
else
{

Check warning on line 47 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L47

Added line #L47 was not covered by tests
return GenerateClass(schema, typeName);
}
}

Check warning on line 51 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L50-L51

Added lines #L50 - L51 were not covered by tests
/// <summary>
/// override to generate JsonInheritanceAttribute, JsonInheritanceConverter with our custom template models
/// code is taken from NJsonSchema.CodeGeneration.CSharp.CSharpGenerator.GenerateTypes

Check warning on line 54 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L53-L54

Added lines #L53 - L54 were not covered by tests
/// </summary>
public override IEnumerable<CodeArtifact> GenerateTypes()
{

Check warning on line 57 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L56-L57

Added lines #L56 - L57 were not covered by tests
var baseArtifacts = base.GenerateTypes();
var artifacts = new List<CodeArtifact>();

Check warning on line 60 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L60

Added line #L60 was not covered by tests
if (baseArtifacts.Any(r => r.Code.Contains("JsonInheritanceConverter")))
{

Check warning on line 62 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L62

Added line #L62 was not covered by tests
if (Settings.ExcludedTypeNames?.Contains("JsonInheritanceAttribute") != true)
{
var template = Settings.TemplateFactory.CreateTemplate("CSharp", "JsonInheritanceAttribute", new CustomJsonInheritanceConverterTemplateModel(Settings, usePolymorphicSerialization));
artifacts.Add(new CodeArtifact("JsonInheritanceAttribute", CodeArtifactType.Class, CodeArtifactLanguage.CSharp, CodeArtifactCategory.Utility, template));
}

Check warning on line 68 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L68

Added line #L68 was not covered by tests
if (Settings.ExcludedTypeNames?.Contains("JsonInheritanceConverter") != true)
{
var template = Settings.TemplateFactory.CreateTemplate("CSharp", "JsonInheritanceConverter", new CustomJsonInheritanceConverterTemplateModel(Settings, usePolymorphicSerialization));
artifacts.Add(new CodeArtifact("JsonInheritanceConverter", CodeArtifactType.Class, CodeArtifactLanguage.CSharp, CodeArtifactCategory.Utility, template));
}

Check warning on line 73 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L73

Added line #L73 was not covered by tests
}

Check warning on line 75 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L75

Added line #L75 was not covered by tests
return baseArtifacts.Concat(artifacts);
}

Check warning on line 77 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L77

Added line #L77 was not covered by tests

/// <summary>
/// Code is taken from NJsonSchema.CodeGeneration.CSharp.CSharpGenerator.GenerateClass
/// to instantiate our custom ClassTemplateModel
/// </summary>

Check warning on line 82 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L82

Added line #L82 was not covered by tests
private CodeArtifact GenerateClass(JsonSchema schema, string typeName)
{

Check warning on line 84 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L84

Added line #L84 was not covered by tests
var model = new CustomClassTemplateModel(typeName, Settings, resolver, schema, RootObject, usePolymorphicSerialization);

Check warning on line 86 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L86

Added line #L86 was not covered by tests
RenamePropertyWithSameNameAsClass(typeName, model.Properties);

var template = Settings.TemplateFactory.CreateTemplate("CSharp", "Class", model);
return new CodeArtifact(typeName, model.BaseClassName, CodeArtifactType.Class, CodeArtifactLanguage.CSharp, CodeArtifactCategory.Contract, template);
}

/// <summary>
/// Code is taken from NJsonSchema.CodeGeneration.CSharp.CSharpGenerator.RenamePropertyWithSameNameAsClass
/// </summary>
private static void RenamePropertyWithSameNameAsClass(string typeName, IEnumerable<PropertyModel> properties)
{
var propertyModels = properties as PropertyModel[] ?? properties.ToArray();
PropertyModel? propertyWithSameNameAsClass = null;
foreach (var p in propertyModels)
{
if (p.PropertyName == typeName)
{
propertyWithSameNameAsClass = p;
break;
}
}

if (propertyWithSameNameAsClass != null)
{
var number = 1;
var candidate = typeName + number;
while (propertyModels.Any(p => p.PropertyName == candidate))
{
number++;

Check warning on line 115 in src/Refitter.Core/CustomCSharpClientGenerator.cs

View check run for this annotation

Codecov / codecov/patch

src/Refitter.Core/CustomCSharpClientGenerator.cs#L115

Added line #L115 was not covered by tests
}

propertyWithSameNameAsClass.PropertyName = propertyWithSameNameAsClass.PropertyName + number;
}
}

/// <summary>
/// finally, our custom ClassTemplateModel and CustomJsonInheritanceConverterTemplateModel
/// to have access to UsePolymorphicSerialization
/// This code should be removed when NSwag supports STJ polymorphic serialization
/// </summary>
private class CustomClassTemplateModel(string typeName, CSharpGeneratorSettings settings, CSharpTypeResolver resolver, JsonSchema schema, object rootObject, bool usePolymorphicSerialization)
: ClassTemplateModel(typeName, settings, resolver, schema, rootObject)
{
public bool UsePolymorphicSerialization => usePolymorphicSerialization;
}

private class CustomJsonInheritanceConverterTemplateModel(CSharpGeneratorSettings settings, bool usePolymorphicSerialization)
: JsonInheritanceConverterTemplateModel(settings)
{
public bool UsePolymorphicSerialization => usePolymorphicSerialization;
}
}
}
4 changes: 4 additions & 0 deletions src/Refitter.Core/Refitter.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,8 @@
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
<EmbeddedResource Include="Templates/*.liquid" />
</ItemGroup>

</Project>
10 changes: 8 additions & 2 deletions src/Refitter.Core/Settings/RefitGeneratorSettings.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json.Serialization;

namespace Refitter.Core;
Expand Down Expand Up @@ -216,4 +216,10 @@ public class RefitGeneratorSettings
/// Dependency Injection is written to a file called DependencyInjection.cs
/// </summary>
public bool GenerateMultipleFiles { get; set; }
}

/// <summary>
/// Set to <c>true</c> to use System.Text.Json polymorphic serialization. Default is <c>false</c>
/// Gets a value indicating whether to use System.Text.Json polymorphic serialization
/// </summary>
public bool UsePolymorphicSerialization { get; set; }
}
Loading
Loading